1# Expect script for linker support of IFUNC symbols and relocations. 2# 3# Copyright 2009, 2010 Free Software Foundation, Inc. 4# Contributed by Red Hat. 5# 6# This file is part of the GNU Binutils. 7# 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. 12# 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. 17# 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, 21# MA 02110-1301, USA. 22# 23# Written by Nick Clifton <nickc@redhat.com> 24 25 26# IFUNC support has only been implemented for the ix86, x86_64, powerpc, 27# and sparc so far. 28if {!(([istarget "i?86-*-*"] 29 || [istarget "x86_64-*-*"] 30 || [istarget "powerpc*-*-*"] 31 || [istarget "sparc*-*-*"]) 32 && ([istarget "*-*-elf*"] 33 || (([istarget "*-*-linux*"] 34 || [istarget "*-*-gnu*"]) 35 && ![istarget "*-*-*aout*"] 36 && ![istarget "*-*-*oldld*"]))) } { 37 verbose "IFUNC tests not run - target does not support IFUNC" 38 return 39} 40 41# We need a native system. FIXME: Strictly speaking this 42# is not true, we just need to know how to create a fully 43# linked executable, including the C and Z libraries, using 44# the linker that is under test. 45if ![isnative] { 46 verbose "IFUNC tests not run - not a native toolchain" 47 return 48} 49 50# We need a working compiler. (Strictly speaking this is 51# not true, we could use target specific assembler files). 52if { [which $CC] == 0 } { 53 verbose "IFUNC tests not run - no compiler available" 54 return 55} 56 57# A procedure to check the OS/ABI field in the ELF header of a binary file. 58proc check_osabi { binary_file expected_osabi } { 59 global READELF 60 global READELFFLAGS 61 62 catch "exec $READELF $READELFFLAGS --file-header $binary_file > readelf.out" got 63 64 if ![string match "" $got] then { 65 verbose "proc check_osabi: Readelf produced unexpected out processing $binary_file: $got" 66 return 0 67 } 68 69 if { ![regexp "\n\[ \]*OS/ABI:\[ \]*(.+)\n\[ \]*ABI" \ 70 [file_contents readelf.out] nil osabi] } { 71 verbose "proc check_osabi: Readelf failed to extract an ELF header from $binary_file" 72 return 0 73 } 74 75 if { $osabi == $expected_osabi } { 76 return 1 77 } 78 79 verbose "Expected OSABI: $expected_osabi, Obtained osabi: $osabi" 80 81 return 0 82} 83 84# A procedure to confirm that a file contains the IFUNC symbol. 85# Returns -1 upon error, 0 if the symbol was not found and 1 if it was found. 86proc contains_ifunc_symbol { binary_file } { 87 global READELF 88 global READELFFLAGS 89 90 catch "exec $READELF $READELFFLAGS --symbols $binary_file > readelf.out" got 91 92 if ![string match "" $got] then { 93 verbose "proc contains_ifunc_symbol: Readelf produced unexpected out processing $binary_file: $got" 94 return -1 95 } 96 97 # Look for a line like this: 98 # 58: 0000000000400600 30 IFUNC GLOBAL DEFAULT 12 library_func2 99 100 if { ![regexp ".*\[ \]*IFUNC\[ \]+GLOBAL\[ \]+DEFAULT\[ \]+\[UND0-9\]+\[ \]+library_func2\n" [file_contents readelf.out]] } { 101 return 0 102 } 103 104 return 1 105} 106 107# A procedure to confirm that a file contains the R_*_IRELATIVE 108# relocation. 109# Returns -1 upon error, 0 if the relocation was not found and 1 if 110# it was found. 111proc contains_irelative_reloc { binary_file } { 112 global READELF 113 global READELFFLAGS 114 115 catch "exec $READELF $READELFFLAGS --relocs --wide $binary_file > readelf.out" got 116 117 if ![string match "" $got] then { 118 verbose "proc contains_irelative_reloc: Readelf produced unexpected out processing $binary_file: $got" 119 return -1 120 } 121 122 # Look for a line like this: 123 # 0000000000600ab0 0000000000000025 R_X86_64_IRELATIVE 000000000040061c 124 # 080496f4 0000002a R_386_IRELATIVE 125 126 127 if { ![regexp "\[0-9a-f\]+\[ \]+\[0-9a-f\]+\[ \]+R_\[_0-9A-Z\]+_IREL(|ATIVE)\[ \]*\[0-9a-f\]*\n" [file_contents readelf.out]] } { 128 return 0 129 } 130 131 return 1 132} 133 134# A procedure to confirm that a file contains a relocation that references an IFUNC symbol. 135# Returns -1 upon error, 0 if the reloc was not found and 1 if it was found. 136proc contains_ifunc_reloc { binary_file } { 137 global READELF 138 global READELFFLAGS 139 140 catch "exec $READELF $READELFFLAGS --relocs $binary_file > readelf.out" got 141 142 if ![string match "" $got] then { 143 verbose "proc contains_ifunc_reloc: Readelf produced unexpected out processing $binary_file: $got" 144 return -1 145 } 146 147 if [string match "" [file_contents readelf.out]] then { 148 verbose "No relocs found in $binary_file" 149 return 0 150 } 151 152 if { ![regexp "\\(\\)" [file_contents readelf.out]] } { 153 return 0 154 } 155 156 return 1 157} 158 159set fails 0 160 161# Create the object files, libraries and executables. 162if ![ld_compile "$CC -c -fPIC" "$srcdir/$subdir/prog.c" "tmpdir/shared_prog.o"] { 163 fail "Could not create a PIC object file" 164 set fails [expr $fails + 1] 165} 166if ![ld_compile "$CC -c" "$srcdir/$subdir/prog.c" "tmpdir/static_prog.o"] { 167 fail "Could not create a non-PIC object file" 168 set fails [expr $fails + 1] 169} 170if ![ld_compile "$CC -c -fPIC -DWITH_IFUNC" "$srcdir/$subdir/lib.c" "tmpdir/shared_ifunc.o"] { 171 fail "Could not create a PIC object file containing an IFUNC symbol" 172 set fails [expr $fails + 1] 173} 174if ![ld_compile "$CC -c -DWITH_IFUNC" "$srcdir/$subdir/lib.c" "tmpdir/static_ifunc.o"] { 175 fail "Could not create a non-PIC object file containing an IFUNC symbol" 176 set fails [expr $fails + 1] 177} 178if ![ld_compile "$CC -c -DWITHOUT_IFUNC" "$srcdir/$subdir/lib.c" "tmpdir/static_noifunc.o"] { 179 fail "Could not create an ordinary non-PIC object file" 180 set fails [expr $fails + 1] 181} 182if ![ld_assemble $as "$srcdir/ld-elf/empty.s" "tmpdir/empty.o"] { 183 fail "Could not create an empty object file" 184 set fails [expr $fails + 1] 185} 186if ![ld_compile "$CC -c" "$srcdir/$subdir/test-1.c" "tmpdir/test-1.o"] { 187 fail "Could not create test-1.o" 188 set fails [expr $fails + 1] 189} 190if ![ld_compile "$CC -fPIC -c" "$srcdir/$subdir/test-2.c" "tmpdir/test-2.o"] { 191 fail "Could not create test-2.o" 192 set fails [expr $fails + 1] 193} 194 195if { $fails != 0 } { 196 return 197} 198 199if ![ld_simple_link $ld "tmpdir/libshared_ifunc.so" "-shared tmpdir/shared_ifunc.o"] { 200 fail "Could not create a shared library containing an IFUNC symbol" 201 set fails [expr $fails + 1] 202} 203if ![ar_simple_create $ar "" "tmpdir/libifunc.a" "tmpdir/static_ifunc.o"] { 204 fail "Could not create a static library containing an IFUNC symbol" 205 set fails [expr $fails + 1] 206} 207 208if { $fails != 0 } { 209 return 210} 211 212if ![default_ld_link $ld "tmpdir/dynamic_prog" "-Ltmpdir tmpdir/shared_prog.o -Bdynamic -lshared_ifunc -rpath ./tmpdir"] { 213 fail "Could not link a dynamic executable" 214 set fails [expr $fails + 1] 215} 216if ![default_ld_link $ld "tmpdir/local_prog" "-Ltmpdir tmpdir/static_prog.o -lifunc"] { 217 fail "Could not link a dynamic executable using local ifunc" 218 set fails [expr $fails + 1] 219} 220if ![default_ld_link $ld "tmpdir/static_prog" "-static -Ltmpdir tmpdir/static_prog.o -lifunc"] { 221 fail "Could not link a static executable" 222 set fails [expr $fails + 1] 223} 224if ![ld_simple_link $ld "tmpdir/static_nonifunc_prog" "-static tmpdir/empty.o"] { 225 fail "Could not link a non-ifunc using static executable" 226 set fails [expr $fails + 1] 227} 228if ![default_ld_link $ld "tmpdir/test-1" "tmpdir/test-1.o tmpdir/libshared_ifunc.so"] { 229 fail "Could not link test-1" 230 set fails [expr $fails + 1] 231} 232if ![ld_simple_link $ld "tmpdir/libtest-2.so" "-shared tmpdir/test-2.o"] { 233 fail "Could not link libtest-2.so" 234 set fails [expr $fails + 1] 235} 236 237if { $fails == 0 } { 238 pass "Building ifunc binaries" 239 set fails 0 240} else { 241 return 242} 243 244# Check the executables and shared libraries 245# 246# The linked ifunc using executables and the shared library containing 247# ifunc should have an OSABI field of LINUX. The linked non-ifunc using 248# executable should have an OSABI field of NONE (aka System V). 249 250if {! [check_osabi tmpdir/libshared_ifunc.so {UNIX - Linux}]} { 251 fail "Shared libraries containing ifunc does not have an OS/ABI field of LINUX" 252 set fails [expr $fails + 1] 253} 254if {! [check_osabi tmpdir/local_prog {UNIX - Linux}]} { 255 fail "Local ifunc-using executable does not have an OS/ABI field of LINUX" 256 set fails [expr $fails + 1] 257} 258if {! [check_osabi tmpdir/static_prog {UNIX - Linux}]} { 259 fail "Static ifunc-using executable does not have an OS/ABI field of LINUX" 260 set fails [expr $fails + 1] 261} 262if {! [check_osabi tmpdir/dynamic_prog {UNIX - System V}]} { 263 fail "Dynamic ifunc-using executable does not have an OS/ABI field of System V" 264 set fails [expr $fails + 1] 265} 266if {! [check_osabi tmpdir/static_nonifunc_prog {UNIX - System V}]} { 267 fail "Static non-ifunc-using executable does not have an OS/ABI field of System V" 268 set fails [expr $fails + 1] 269} 270 271# The linked ifunc using executables and the shared library containing 272# ifunc should contain an IFUNC symbol. The non-ifunc using executable 273# should not. 274 275if {[contains_ifunc_symbol tmpdir/libshared_ifunc.so] != 1} { 276 fail "Shared libraries containing ifunc does not contain an IFUNC symbol" 277 set fails [expr $fails + 1] 278} 279if {[contains_ifunc_symbol tmpdir/local_prog] != 1} { 280 fail "Local ifunc-using executable does not contain an IFUNC symbol" 281 set fails [expr $fails + 1] 282} 283if {[contains_ifunc_symbol tmpdir/static_prog] != 1} { 284 fail "Static ifunc-using executable does not contain an IFUNC symbol" 285 set fails [expr $fails + 1] 286} 287if {[contains_ifunc_symbol tmpdir/dynamic_prog] != 0} { 288 fail "Dynamic ifunc-using executable contains an IFUNC symbol" 289 set fails [expr $fails + 1] 290} 291if {[contains_ifunc_symbol tmpdir/static_nonifunc_prog] != 0} { 292 fail "Static non-ifunc-using executable contains an IFUNC symbol" 293 set fails [expr $fails + 1] 294} 295if {[contains_ifunc_symbol tmpdir/test-1] != 0} { 296 fail "test-1 contains IFUNC symbols" 297 set fails [expr $fails + 1] 298} 299if {[contains_ifunc_symbol tmpdir/libtest-2.so] != 0} { 300 fail "libtest-2.so contains IFUNC symbols" 301 set fails [expr $fails + 1] 302} 303 304# The linked ifunc using executables and shared libraries should contain 305# a dynamic reloc referencing the IFUNC symbol. (Even the static 306# executable which should have a dynamic section created for it). The 307# non-ifunc using executable should not. 308 309if {[contains_irelative_reloc tmpdir/libshared_ifunc.so] != 1} { 310 fail "ifunc-using shared library does not contain R_*_IRELATIVE relocation" 311 set fails [expr $fails + 1] 312} 313if {[contains_irelative_reloc tmpdir/local_prog] != 1} { 314 fail "Local ifunc-using executable does not contain R_*_IRELATIVE relocation" 315 set fails [expr $fails + 1] 316} 317if {[contains_irelative_reloc tmpdir/static_prog] != 1} { 318 fail "Static ifunc-using executable does not contain R_*_IRELATIVE relocation" 319 set fails [expr $fails + 1] 320} 321if {[contains_ifunc_reloc tmpdir/dynamic_prog] != 0} { 322 fail "Dynamic ifunc-using executable contains a reloc against an IFUNC symbol" 323 set fails [expr $fails + 1] 324} 325if {[contains_ifunc_reloc tmpdir/static_nonifunc_prog] == 1} { 326 fail "Static non-ifunc-using executable contains a reloc against an IFUNC symbol!" 327 set fails [expr $fails + 1] 328} 329 330if { $fails == 0 } { 331 pass "Checking ifunc binaries" 332} 333 334# Clean up, unless we are being verbose, in which case we leave the files available. 335if { $verbose < 1 } { 336 remote_file host delete "tmpdir/shared_prog.o" 337 remote_file host delete "tmpdir/static_prog.o" 338 remote_file host delete "tmpdir/shared_ifunc.o" 339 remote_file host delete "tmpdir/static_ifunc.o" 340 remote_file host delete "tmpdir/static_noifunc.o" 341 remote_file host delete "tmpdir/libshared_ifunc.so" 342 remote_file host delete "tmpdir/libifunc.a" 343 remote_file host delete "tmpdir/dynamic_prog" 344 remote_file host delete "tmpdir/local_prog" 345 remote_file host delete "tmpdir/static_prog" 346 remote_file host delete "tmpdir/static_nonifunc_prog" 347} 348 349set test_list [lsort [glob -nocomplain $srcdir/$subdir/*.d]] 350foreach t $test_list { 351 # We need to strip the ".d", but can leave the dirname. 352 verbose [file rootname $t] 353 run_dump_test [file rootname $t] 354} 355