1 # Expect script
for linker support of IFUNC symbols and relocations.
3 # Copyright
(C
) 2009-2024 Free Software Foundation
, Inc.
4 # Contributed by Red Hat.
6 # This file is part of the GNU Binutils.
8 # This
program is free software
; you can redistribute it and
/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation
; either version
3 of the License
, or
11 #
(at your option
) any later version.
13 # This
program is distributed in the hope that it will be useful
,
14 # but WITHOUT
ANY WARRANTY
; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License
for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with this
program; if not
, write to the Free Software
20 # Foundation
, Inc.
, 51 Franklin Street
- Fifth Floor
, Boston
,
23 # Written by Nick Clifton
<nickc@redhat.com
>
26 if { ![is_elf_format
] ||
![supports_gnu_osabi
]
27 ||
[istarget alpha
-*-*]
28 ||
[istarget arc
*-*-*]
29 ||
[istarget am33
*-*-*]
30 ||
[istarget bfin
-*-*]
31 ||
[istarget cris
*-*-*]
33 ||
[istarget kvx
*-*-*]
34 ||
[istarget lm32
-*-*]
35 ||
[istarget m32r
-*-*]
36 ||
[istarget m68k
-*-*]
37 ||
[istarget microblaze
-*-*]
38 ||
[istarget mips
*-*-*]
39 ||
[istarget mn10300
-*-*]
40 ||
[istarget nds32
*-*-*]
41 ||
[istarget nios2
-*-*]
42 ||
[istarget or1k
-*-*]
43 ||
[istarget score
*-*-*]
45 ||
[istarget tic6x
-*-*]
46 ||
[istarget tile
*-*-*]
47 ||
[istarget vax
-*-*] } {
48 verbose
"IFUNC tests not run - target does not support IFUNC"
52 # Skip targets where
-shared is not supported
54 if ![check_shared_lib_support
] {
58 set saved_ASFLAGS
"$ASFLAGS"
59 if { [istarget
"i?86-*-*"] || [istarget "x86_64-*-*"] } {
60 set ASFLAGS
"$ASFLAGS -mx86-used-note=no"
63 # This test does not need a compiler...
64 run_dump_test
"ifuncmod5"
66 set test_list
[lsort
[glob
-nocomplain $srcdir
/$subdir
/*.d
]]
67 foreach t $test_list
{
68 # We need to
strip the
".d", but can leave the dirname.
69 verbose
[file rootname $t
]
70 run_dump_test
[file rootname $t
]
73 # We need a working compiler.
(Strictly speaking this is
74 # not true
, we could use target specific assembler files
).
75 if { ![check_compiler_available
] } {
76 verbose
"IFUNC tests not run - no compiler available"
80 # A procedure to check the OS
/ABI field in the ELF header of a binary file.
81 proc check_osabi
{ binary_file expected_osabi
} {
85 catch
"exec $READELF $READELFFLAGS --file-header $binary_file > readelf.out" got
87 if ![string match
"" $got] then {
88 verbose
"proc check_osabi: Readelf produced unexpected out processing $binary_file: $got"
92 if { ![regexp
"\n\[ \]*OS/ABI:\[ \]*(.+)\n\[ \]*ABI" \
93 [file_contents readelf.out
] nil osabi
] } {
94 verbose
"proc check_osabi: Readelf failed to extract an ELF header from $binary_file"
98 if { $osabi
== $expected_osabi
} {
102 verbose
"Expected OSABI: $expected_osabi, Obtained osabi: $osabi"
107 # A procedure to confirm that a file contains the IFUNC symbol.
108 # Returns
-1 upon error
, 0 if the symbol was not found and
1 if it was found.
109 proc contains_ifunc_symbol
{ binary_file
} {
113 catch
"exec $READELF $READELFFLAGS --symbols $binary_file > readelf.out" got
115 if ![string match
"" $got] then {
116 verbose
"proc contains_ifunc_symbol: Readelf produced unexpected out processing $binary_file: $got"
120 # Look
for a line like this
:
121 #
58: 0000000000400600 30 IFUNC GLOBAL DEFAULT
12 library_func2
122 # with perhaps some other
info between the visibility and section
124 if { ![regexp
".*\[ \]*IFUNC\[ \]+GLOBAL\[ \]+DEFAULT .* \[UND0-9\]+\[ \]+library_func2\n" [file_contents readelf.out]] } {
131 # A procedure to confirm that a file contains the R_
*_IRELATIVE
133 # Returns
-1 upon error
, 0 if the relocation was not found and
1 if
135 proc contains_irelative_reloc
{ binary_file
} {
139 catch
"exec $READELF $READELFFLAGS --relocs --wide $binary_file > readelf.out" got
141 if ![string match
"" $got] then {
142 verbose
"proc contains_irelative_reloc: Readelf produced unexpected out processing $binary_file: $got"
146 # Look
for a line like this
:
147 #
0000000000600ab0
0000000000000025 R_X86_64_IRELATIVE
000000000040061c
148 #
080496f4
0000002a R_386_IRELATIVE
151 if { ![regexp
"\[0-9a-f\]+\[ \]+\[0-9a-f\]+\[ \]+R_(\[_0-9A-Z\]+_IREL(|ATIVE)|PARISC_IPLT).*\n" [file_contents readelf.out]] } {
158 # A procedure to confirm that a file contains a relocation that references an IFUNC symbol.
159 # Returns
-1 upon error
, 0 if the reloc was not found and
1 if it was found.
160 proc contains_ifunc_reloc
{ binary_file
} {
164 catch
"exec $READELF $READELFFLAGS --relocs $binary_file > readelf.out" got
166 if ![string match
"" $got] then {
167 verbose
"proc contains_ifunc_reloc: Readelf produced unexpected out processing $binary_file: $got"
171 if [string match
"" [file_contents readelf.out]] then {
172 verbose
"No relocs found in $binary_file"
176 if { ![regexp
"\\(\\)" [file_contents readelf.out]] } {
185 # Disable LTO
for these tests.
186 set cc_cmd
"$CC_FOR_TARGET"
187 if {[check_lto_available
]} {
188 append cc_cmd
" -fno-lto"
191 # Create the object files
, libraries and executables.
192 if ![ld_compile
"$cc_cmd -c -fPIC" "$srcdir/$subdir/prog.c" "tmpdir/shared_prog.o"] {
193 fail
"Could not create a PIC object file"
194 set fails
[expr $fails
+ 1]
196 if ![ld_compile
"$cc_cmd -c $NOPIE_CFLAGS" "$srcdir/$subdir/prog.c" "tmpdir/static_prog.o"] {
197 fail
"Could not create a non-PIC object file"
198 set fails
[expr $fails
+ 1]
200 if ![ld_compile
"$cc_cmd -c -fPIC -DWITH_IFUNC" "$srcdir/$subdir/lib.c" "tmpdir/shared_ifunc.o"] {
201 fail
"Could not create a PIC object file containing an IFUNC symbol"
202 set fails
[expr $fails
+ 1]
204 if ![ld_compile
"$cc_cmd -c $NOPIE_CFLAGS -DWITH_IFUNC" "$srcdir/$subdir/lib.c" "tmpdir/static_ifunc.o"] {
205 fail
"Could not create a non-PIC object file containing an IFUNC symbol"
206 set fails
[expr $fails
+ 1]
208 if ![ld_compile
"$cc_cmd -c -DWITHOUT_IFUNC" "$srcdir/$subdir/lib.c" "tmpdir/static_noifunc.o"] {
209 fail
"Could not create an ordinary non-PIC object file"
210 set fails
[expr $fails
+ 1]
212 if ![ld_assemble $as
"$srcdir/ld-elf/empty.s" "tmpdir/empty.o"] {
213 fail
"Could not create an empty object file"
214 set fails
[expr $fails
+ 1]
216 if ![ld_compile
"$cc_cmd -c" "$srcdir/$subdir/test-1.c" "tmpdir/test-1.o"] {
217 fail
"Could not create test-1.o"
218 set fails
[expr $fails
+ 1]
220 if ![ld_compile
"$cc_cmd -fPIC -c" "$srcdir/$subdir/test-2.c" "tmpdir/test-2.o"] {
221 fail
"Could not create test-2.o"
222 set fails
[expr $fails
+ 1]
229 if ![ld_link $
ld "tmpdir/libshared_ifunc.so" "-shared tmpdir/shared_ifunc.o"] {
230 fail
"Could not create a shared library containing an IFUNC symbol"
231 set fails
[expr $fails
+ 1]
233 if ![ar_simple_create $ar
"" "tmpdir/libifunc.a" "tmpdir/static_ifunc.o"] {
234 fail
"Could not create a static library containing an IFUNC symbol"
235 set fails
[expr $fails
+ 1]
242 if ![ld_link $CC_FOR_TARGET
"tmpdir/dynamic_prog" "-Wl,--no-as-needed,-rpath=./tmpdir,-Bdynamic -Ltmpdir tmpdir/shared_prog.o -lshared_ifunc"] {
243 fail
"Could not link a dynamic executable"
244 set fails
[expr $fails
+ 1]
246 if ![ld_link $CC_FOR_TARGET
"tmpdir/local_prog" "$NOPIE_LDFLAGS -Wl,--no-as-needed,-rpath=./tmpdir -Ltmpdir tmpdir/static_prog.o -lifunc"] {
247 fail
"Could not link a dynamic executable using local ifunc"
248 set fails
[expr $fails
+ 1]
250 if ![string match
"" $STATIC_LDFLAGS] {
251 if ![ld_link $CC_FOR_TARGET
"tmpdir/static_prog" "-static -Ltmpdir tmpdir/static_prog.o -lifunc"] {
252 fail
"Could not link a static executable"
253 set fails
[expr $fails
+ 1]
256 if ![ld_link $
ld "tmpdir/static_nonifunc_prog" "-static tmpdir/empty.o"] {
257 fail
"Could not link a non-ifunc using static executable"
258 set fails
[expr $fails
+ 1]
260 if ![ld_link $CC_FOR_TARGET
"tmpdir/test-1" "-Wl,--no-as-needed,-rpath=./tmpdir tmpdir/test-1.o tmpdir/libshared_ifunc.so"] {
261 fail
"Could not link test-1"
262 set fails
[expr $fails
+ 1]
264 if ![ld_link $
ld "tmpdir/libtest-2.so" "-shared tmpdir/test-2.o"] {
265 fail
"Could not link libtest-2.so"
266 set fails
[expr $fails
+ 1]
268 if ![ld_link $
ld "tmpdir/libtest-2-now.so" "-shared -z now tmpdir/test-2.o"] {
269 fail
"Could not link libtest-2-now.so"
270 set fails
[expr $fails
+ 1]
274 pass
"Building ifunc binaries"
280 # Check the executables and shared libraries
282 # The linked ifunc using executables and the shared library containing
283 # ifunc should have an OSABI field of GNU. The linked non
-ifunc using
284 # executable should have an OSABI field of
NONE (aka
System V
).
286 switch -glob $target_triplet
{
287 hppa
*-*-linux
* { set expected_none
{UNIX
- GNU
} }
288 default
{ set expected_none
{UNIX
- System V
} }
291 if {! [check_osabi tmpdir
/libshared_ifunc.so
{UNIX
- GNU
}]} {
292 fail
"Shared libraries containing ifunc does not have an OS/ABI field of GNU"
293 set fails
[expr $fails
+ 1]
295 if {! [check_osabi tmpdir
/local_prog
{UNIX
- GNU
}]} {
296 fail
"Local ifunc-using executable does not have an OS/ABI field of GNU"
297 set fails
[expr $fails
+ 1]
299 if { ![string match
"" $STATIC_LDFLAGS] \
300 && ![check_osabi tmpdir
/static_prog
{UNIX
- GNU
}]} {
301 fail
"Static ifunc-using executable does not have an OS/ABI field of GNU"
302 set fails
[expr $fails
+ 1]
304 if {! [check_osabi tmpdir
/dynamic_prog $expected_none
]} {
305 fail
"Dynamic ifunc-using executable does not have an OS/ABI field of $expected_none"
306 set fails
[expr $fails
+ 1]
308 if {! [check_osabi tmpdir
/static_nonifunc_prog $expected_none
]} {
309 fail
"Static non-ifunc-using executable does not have an OS/ABI field of $expected_none"
310 set fails
[expr $fails
+ 1]
313 # The linked ifunc using executables and the shared library containing
314 # ifunc should contain an IFUNC symbol. The non
-ifunc using executable
317 if {[contains_ifunc_symbol tmpdir
/libshared_ifunc.so
] != 1} {
318 fail
"Shared libraries containing ifunc does not contain an IFUNC symbol"
319 set fails
[expr $fails
+ 1]
321 if {[contains_ifunc_symbol tmpdir
/local_prog
] != 1} {
322 fail
"Local ifunc-using executable does not contain an IFUNC symbol"
323 set fails
[expr $fails
+ 1]
325 if { ![string match
"" $STATIC_LDFLAGS] \
326 && [contains_ifunc_symbol tmpdir
/static_prog
] != 1} {
327 fail
"Static ifunc-using executable does not contain an IFUNC symbol"
328 set fails
[expr $fails
+ 1]
330 if {[contains_ifunc_symbol tmpdir
/dynamic_prog
] != 0} {
331 fail
"Dynamic ifunc-using executable contains an IFUNC symbol"
332 set fails
[expr $fails
+ 1]
334 if {[contains_ifunc_symbol tmpdir
/static_nonifunc_prog
] != 0} {
335 fail
"Static non-ifunc-using executable contains an IFUNC symbol"
336 set fails
[expr $fails
+ 1]
338 if {[contains_ifunc_symbol tmpdir
/test
-1] != 0} {
339 fail
"test-1 contains IFUNC symbols"
340 set fails
[expr $fails
+ 1]
342 if {[contains_ifunc_symbol tmpdir
/libtest
-2.so
] != 0} {
343 fail
"libtest-2.so contains IFUNC symbols"
344 set fails
[expr $fails
+ 1]
346 if {[contains_ifunc_symbol tmpdir
/libtest
-2-now.so
] != 0} {
347 fail
"libtest-2-now.so contains IFUNC symbols"
348 set fails
[expr $fails
+ 1]
351 # The linked ifunc using executables and shared libraries should contain
352 # a dynamic reloc referencing the IFUNC symbol.
(Even the static
353 # executable which should have a dynamic section created
for it
). The
354 # non
-ifunc using executable should not.
356 if {[contains_irelative_reloc tmpdir
/libshared_ifunc.so
] != 1} {
357 fail
"ifunc-using shared library does not contain R_*_IRELATIVE relocation"
358 set fails
[expr $fails
+ 1]
360 if {[contains_irelative_reloc tmpdir
/local_prog
] != 1} {
361 fail
"Local ifunc-using executable does not contain R_*_IRELATIVE relocation"
362 set fails
[expr $fails
+ 1]
364 if { ![string match
"" $STATIC_LDFLAGS] \
365 && ![istarget hppa
*-*-*] \
366 && [contains_irelative_reloc tmpdir
/static_prog
] != 1} {
367 fail
"Static ifunc-using executable does not contain R_*_IRELATIVE relocation"
368 set fails
[expr $fails
+ 1]
370 if {[contains_ifunc_reloc tmpdir
/dynamic_prog
] != 0} {
371 fail
"Dynamic ifunc-using executable contains a reloc against an IFUNC symbol"
372 set fails
[expr $fails
+ 1]
374 if {[contains_ifunc_reloc tmpdir
/static_nonifunc_prog
] == 1} {
375 fail
"Static non-ifunc-using executable contains a reloc against an IFUNC symbol!"
376 set fails
[expr $fails
+ 1]
380 pass
"Checking ifunc binaries"
383 run_cc_link_tests
[list \
385 "Build libpr16467a.so" \
386 "-shared -Wl,--version-script=pr16467a.map" \
393 "Build libpr16467b.a" \
401 "Build libpr16467b.so" \
402 "-shared -Wl,--as-needed tmpdir/pr16467b.o tmpdir/libpr16467a.so \
403 -Wl
,--version
-script
=pr16467b.map
" \
410 "Build libpr16467c.a" \
418 "Build libpr16467an.so" \
419 "-shared -Wl,-z,now -Wl,--version-script=pr16467a.map" \
426 "Build libpr16467bn.so" \
427 "-shared -Wl,--as-needed tmpdir/pr16467b.o tmpdir/libpr16467an.so \
428 -Wl
,--version
-script
=pr16467b.map
" \
436 run_ld_link_exec_tests
[list \
438 "Common symbol override ifunc test 1a" \
441 { ifunc
-common
-1a.c ifunc
-common
-1b.c
} \
443 "ifunc-common-1.out" \
447 "Common symbol override ifunc test 1b" \
450 { ifunc
-common
-1b.c ifunc
-common
-1a.c
} \
452 "ifunc-common-1.out" \
457 # Run
-time tests which require working IFUNC support.
458 if { ![check_ifunc_available
] } {
462 run_cc_link_tests
[list \
464 "Build ifunc-lib.so" \
472 "Build ifunc-libn.so" \
473 "-shared -Wl,-z,now" \
481 run_ld_link_exec_tests
[list \
484 "-Wl,--no-as-needed tmpdir/pr16467c.o tmpdir/libpr16467b.so tmpdir/libpr16467a.so" \
492 "Run pr16467 (-z now)" \
493 "-Wl,-z,now -Wl,--no-as-needed tmpdir/pr16467c.o tmpdir/libpr16467bn.so tmpdir/libpr16467an.so" \
502 "-Wl,--no-as-needed tmpdir/libifunc-lib.so" \
509 "Run ifunc-main with -fpic" \
510 "-Wl,--no-as-needed tmpdir/libifunc-lib.so" \
518 "Run ifunc-main (-z now)" \
519 "-Wl,-z,now -Wl,--no-as-needed tmpdir/libifunc-libn.so" \
526 "Run ifunc-main with PIE (-z now)" \
527 "-pie -Wl,-z,now -Wl,--no-as-needed tmpdir/libifunc-libn.so" \
536 # Run
-time tests which require working ifunc attribute support.
537 if { ![check_ifunc_attribute_available
] } {
541 run_cc_link_tests
[list \
551 "Build libpr18808.so" \
559 "Build libpr18808n.so" \
560 "-shared -Wl,-z,now" \
575 "Build libpr18841b.so" \
583 "Build libpr18841c.so" \
591 "Build libpr18841bn.so" \
592 "-Wl,-z,now -shared" \
599 "Build libpr18841cn.so" \
601 "-Wl,-z,now -fPIC -O0 -g" \
607 "Build libpr23169a.so" \
608 "-shared -Wl,-z,lazy" \
615 "Build libpr23169b.so" \
616 "-shared -Wl,-z,now" \
624 "$NOPIE_LDFLAGS -Wl,--no-as-needed tmpdir/libpr23169a.so" \
625 "$NOPIE_CFLAGS -O2 -g" \
626 { pr23169b.c pr23169c.c
} \
627 {{readelf
{--dyn
-syms
} pr23169a.rd
} \
628 {readelf
{-r
-W
} pr23169b.rd
}} \
633 "-pie -Wl,--no-as-needed tmpdir/libpr23169a.so" \
635 { pr23169b.c pr23169c.c
} \
636 {{readelf
{--dyn
-syms
} pr23169c.rd
} \
637 {readelf
{-r
-W
} pr23169b.rd
}} \
642 "$NOPIE_LDFLAGS -Wl,--no-as-needed tmpdir/libpr23169a.so" \
644 { pr23169b.c pr23169c.c
} \
645 {{readelf
{--dyn
-syms
} pr23169a.rd
} \
646 {readelf
{-r
-W
} pr23169b.rd
}} \
651 "$NOPIE_LDFLAGS -Wl,--no-as-needed,-z,now tmpdir/libpr23169b.so" \
652 "$NOPIE_CFLAGS -O2 -g" \
653 { pr23169b.c pr23169c.c
} \
654 {{readelf
{--dyn
-syms
} pr23169a.rd
} \
655 {readelf
{-r
-W
} pr23169b.rd
}} \
660 "$NOPIE_LDFLAGS -Wl,--no-as-needed,-z,now tmpdir/libpr23169b.so" \
662 { pr23169b.c pr23169c.c
} \
663 {{readelf
{--dyn
-syms
} pr23169a.rd
} \
664 {readelf
{-r
-W
} pr23169b.rd
}} \
669 run_ld_link_exec_tests
[list \
672 "-Wl,--no-as-needed tmpdir/pr18808a.o tmpdir/libpr18808.so" \
679 "Run pr18808 (-z now)" \
680 "-Wl,-z,now -Wl,--no-as-needed tmpdir/pr18808a.o tmpdir/libpr18808n.so" \
687 "Run pr18841 with libpr18841b.so" \
688 "$NOPIE_LDFLAGS -Wl,--no-as-needed tmpdir/pr18841a.o tmpdir/libpr18841b.so" \
695 "Run pr18841 with libpr18841c.so" \
696 "$NOPIE_LDFLAGS -Wl,--as-needed tmpdir/pr18841a.o tmpdir/libpr18841c.so" \
703 "Run pr18841 with libpr18841bn.so (-z now)" \
704 "$NOPIE_LDFLAGS -Wl,-z,now -Wl,--no-as-needed tmpdir/pr18841a.o tmpdir/libpr18841bn.so" \
711 "Run pr18841 with libpr18841cn.so (-z now)" \
712 "$NOPIE_LDFLAGS -Wl,-z,now -Wl,--as-needed tmpdir/pr18841a.o tmpdir/libpr18841cn.so" \
729 # The pr23169 testcase is not valid. In general
, you can
't call ifunc
730 # resolvers in another binary unless you know what you're doing. In
731 # particular you must ensure that the binary containing the resolver
732 # is relocated before the resolver is called
(for example
, the
733 # function addresses returned by the resolver may be loaded from the
735 # That does not happen
for the pr23169 testcase where the resolver is
736 # in the executable
(which is relocated last by
ld.so
).
738 && !([istarget
"powerpc-*-*"]
739 ||
[istarget
"aarch64*-*-*"]
740 ||
[istarget
"arm*-*-*"]
741 ||
[istarget
"sparc*-*-*"]
742 ||
[istarget
"riscv*-*-*"]) } {
743 run_ld_link_exec_tests
[list \
746 "$NOPIE_LDFLAGS -Wl,--no-as-needed tmpdir/libpr23169a.so" \
748 { pr23169b.c pr23169c.c
} \
751 "$NOPIE_CFLAGS -O2 -g" \
755 "-pie -Wl,--no-as-needed,-z,lazy tmpdir/libpr23169a.so" \
757 { pr23169b.c pr23169c.c
} \
764 "$NOPIE_LDFLAGS -Wl,--no-as-needed tmpdir/libpr23169a.so" \
766 { pr23169b.c pr23169c.c
} \
773 "$NOPIE_LDFLAGS -Wl,--no-as-needed,-z,now tmpdir/libpr23169b.so" \
775 { pr23169b.c pr23169c.c
} \
778 "$NOPIE_CFLAGS -O2 -g" \
782 "$NOPIE_LDFLAGS -Wl,--no-as-needed,-z,now tmpdir/libpr23169b.so" \
784 { pr23169b.c pr23169c.c
} \
790 if { $STATIC_PIE_LDFLAGS
!= "" } then {
791 run_ld_link_exec_tests
[list \
794 "$STATIC_PIE_LDFLAGS" \
796 { pr23169a.c pr23169b.c pr23169c.c
} \
805 set ASFLAGS
"$saved_ASFLAGS"