1/* Test if an executable can read from the TLS from an STT_GNU_IFUNC resolver.
2 Copyright (C) 2017-2022 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 <https://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
25__thread int bar;
26extern __thread int bar_gd asm ("bar") __attribute__ ((tls_model("global-dynamic")));
27static int *bar_ptr = NULL;
28
29static uint32_t resolver_platform = 0;
30
31int foo (void);
32
33int 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
44uint32_t
45get_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 : "n" (__ATPLATOFF), "b" (tp));
53
54 return tmp;
55}
56
57void
58init_foo (void)
59{
60 bar_ptr = &bar_gd;
61}
62
63int
64my_foo (void)
65{
66 printf (format: "&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
72void
73init_tcb_test (void)
74{
75 resolver_platform = get_platform ();
76}
77
78int
79my_tcb_test (void)
80{
81 printf (format: "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
89static int
90do_test (void)
91{
92 int ret = 0;
93
94 if (foo ())
95 printf (format: "PASS: foo IFUNC resolver called once.\n");
96 else
97 {
98 printf (format: "FAIL: foo IFUNC resolver not called once.\n");
99 ret = 1;
100 }
101
102 if (&bar == bar_ptr)
103 printf (format: "PASS: bar address read from IFUNC resolver is correct.\n");
104 else
105 {
106 printf (format: "FAIL: bar address read from IFUNC resolver is incorrect.\n");
107 ret = 1;
108 }
109
110 if (tcb_test ())
111 printf (format: "PASS: tcb_test IFUNC resolver called once.\n");
112 else
113 {
114 printf (format: "FAIL: tcb_test IFUNC resolver not called once.\n");
115 ret = 1;
116 }
117
118 if (resolver_platform == get_platform ())
119 printf (format: "PASS: platform read from IFUNC resolver is correct.\n");
120 else
121 {
122 printf (format: "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>
130

source code of glibc/sysdeps/powerpc/tst-tlsifunc.c