Jim Cownie | 5e8470a | 2013-09-27 10:38:44 +0000 | [diff] [blame] | 1 | #!/usr/bin/perl |
| 2 | |
| 3 | # |
| 4 | #//===----------------------------------------------------------------------===// |
| 5 | #// |
Chandler Carruth | 57b08b0 | 2019-01-19 10:56:40 +0000 | [diff] [blame] | 6 | #// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 7 | #// See https://llvm.org/LICENSE.txt for license information. |
| 8 | #// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
Jim Cownie | 5e8470a | 2013-09-27 10:38:44 +0000 | [diff] [blame] | 9 | #// |
| 10 | #//===----------------------------------------------------------------------===// |
| 11 | # |
| 12 | |
| 13 | use strict; |
| 14 | use warnings; |
| 15 | |
| 16 | use FindBin; |
| 17 | use lib "$FindBin::Bin/lib"; |
| 18 | |
Jim Cownie | 5e8470a | 2013-09-27 10:38:44 +0000 | [diff] [blame] | 19 | use tools; |
| 20 | |
| 21 | our $VERSION = "0.004"; |
Jonathan Peyton | 4c91ad1 | 2016-01-26 19:44:31 +0000 | [diff] [blame] | 22 | my $target_os; |
| 23 | my $target_arch; |
| 24 | my $target_mic_arch; |
Jim Cownie | 5e8470a | 2013-09-27 10:38:44 +0000 | [diff] [blame] | 25 | |
| 26 | my $hex = qr{[0-9a-f]}i; # hex digit. |
| 27 | |
Andrey Churbanov | d315cea | 2015-01-16 12:54:51 +0000 | [diff] [blame] | 28 | # mic-specific details. |
Jim Cownie | 5e8470a | 2013-09-27 10:38:44 +0000 | [diff] [blame] | 29 | |
Andrey Churbanov | d315cea | 2015-01-16 12:54:51 +0000 | [diff] [blame] | 30 | sub bad_mic_fmt($) { |
Jim Cownie | 5e8470a | 2013-09-27 10:38:44 +0000 | [diff] [blame] | 31 | # Before we allowed both elf64-x86-64-freebsd and elf-l1om-freebsd. |
| 32 | # Now the first one is obsolete, only elf64-l1om-freebsd is allowed. |
| 33 | my ( $fmt ) = @_; |
| 34 | if ( 0 ) { |
Andrey Churbanov | d315cea | 2015-01-16 12:54:51 +0000 | [diff] [blame] | 35 | } elsif ( "$target_mic_arch" eq "knf" ) { |
Jim Cownie | 5e8470a | 2013-09-27 10:38:44 +0000 | [diff] [blame] | 36 | return $fmt !~ m{\Aelf64-l1om?\z}; |
Andrey Churbanov | d315cea | 2015-01-16 12:54:51 +0000 | [diff] [blame] | 37 | } elsif ( "$target_mic_arch" eq "knc" ) { |
Jim Cownie | 5e8470a | 2013-09-27 10:38:44 +0000 | [diff] [blame] | 38 | return $fmt !~ m{\Aelf64-k1om?\z}; |
| 39 | } else { |
| 40 | return 1; |
| 41 | }; |
Andrey Churbanov | d315cea | 2015-01-16 12:54:51 +0000 | [diff] [blame] | 42 | }; # sub bad_mic_fmt |
Jim Cownie | 5e8470a | 2013-09-27 10:38:44 +0000 | [diff] [blame] | 43 | |
Andrey Churbanov | d315cea | 2015-01-16 12:54:51 +0000 | [diff] [blame] | 44 | # Undesired instructions for mic: all x87 and some other. |
Jim Cownie | 5e8470a | 2013-09-27 10:38:44 +0000 | [diff] [blame] | 45 | # AC: Since compiler 2010-06-30 x87 instructions are supported, removed the check of x87. |
Andrey Churbanov | d315cea | 2015-01-16 12:54:51 +0000 | [diff] [blame] | 46 | my $mic_bad_re; |
| 47 | sub bad_mic_instr($$) { |
Jim Cownie | 5e8470a | 2013-09-27 10:38:44 +0000 | [diff] [blame] | 48 | my ( $instr, $args ) = @_; |
Andrey Churbanov | d315cea | 2015-01-16 12:54:51 +0000 | [diff] [blame] | 49 | if ( "$target_mic_arch" eq "knc" ) { |
Jim Cownie | 5e8470a | 2013-09-27 10:38:44 +0000 | [diff] [blame] | 50 | # workaround of bad code generation on KNF Linux* OS: |
Andrey Churbanov | d315cea | 2015-01-16 12:54:51 +0000 | [diff] [blame] | 51 | return ( defined( $instr ) and $instr =~ $mic_bad_re ); |
Jim Cownie | 5e8470a | 2013-09-27 10:38:44 +0000 | [diff] [blame] | 52 | } else { |
Andrey Churbanov | d315cea | 2015-01-16 12:54:51 +0000 | [diff] [blame] | 53 | return ( defined( $instr ) and $instr =~ $mic_bad_re or defined( $args ) and $args =~ m{xmm}i ); |
Jim Cownie | 5e8470a | 2013-09-27 10:38:44 +0000 | [diff] [blame] | 54 | } |
Andrey Churbanov | d315cea | 2015-01-16 12:54:51 +0000 | [diff] [blame] | 55 | }; # sub bad_mic_instr |
Jim Cownie | 5e8470a | 2013-09-27 10:38:44 +0000 | [diff] [blame] | 56 | |
| 57 | # lin_32-specific details. |
| 58 | |
| 59 | sub bad_ia32_fmt($) { |
| 60 | my ( $fmt ) = @_; |
| 61 | return $fmt !~ m{\Aelf32-i386\z}; |
| 62 | }; # sub bad_ia32_fmt |
| 63 | |
| 64 | my @sse2 = |
| 65 | qw{ |
| 66 | movapd movupd movhpd movlpd movmskpd movsd |
| 67 | addpd addsd subpd subsd mulpd mulsd divpd divsd sqrtpd sqrtsd maxpd maxsd minpd minsd |
| 68 | andpd andnpd orpd xorpd |
| 69 | cmppd cmpsd comisd ucomisd |
| 70 | shufpd unpckhpd unpcklpd |
| 71 | cvtpd2pi cvttpd2pi cvtpi2pd cvtpd2dq cvttpd2dq cvtdq2pd cvtps2pd cvtpd2ps cvtss2sd cvtsd2ss |
| 72 | cvtsd2si cvttsd2si cvtsi2sd cvtdq2ps cvtps2dq cvttps2dq movdqa movdqu movq2dq movdq2q |
| 73 | pmuludq paddq psubq pshuflw pshufhw pshufd pslldq psrldq punpckhqdq punpcklqdq clflush |
| 74 | lfence mfence maskmovdqu movntpd movntdq movnti |
| 75 | }; |
| 76 | my @sse3 = |
| 77 | qw{ |
| 78 | fisttp lddqu addsubps addsubpd haddps hsubps haddpd hsubpd movshdup movsldup movddup monitor |
| 79 | mwait |
| 80 | }; |
| 81 | my @ssse3 = |
| 82 | qw{ |
| 83 | phaddw phaddsw phaddd phsubw phsubsw phsubd pabsb pabsw pabsd pmaddubsw pmulhrsw pshufb |
| 84 | psignb psignw psignd palignr |
| 85 | }; |
| 86 | my @sse4 = |
| 87 | ( |
| 88 | # SSE4.1 |
| 89 | qw{ |
| 90 | pmulld pmuldq dppd dpps movntdqa blendpd blendps blendvpd blendvps pblendvb pblendw pminuw |
| 91 | pminud pminsb pminsd pmaxuw pmaxud pmaxsb pmaxsd roundps roundpd roundss roundsd extractps |
| 92 | insertps pinsrb pinsrd pinsrq pextrb pextrw pextrd pextrq pmovsxbw pmovzxbw pmovsxbd |
| 93 | pmovzxbd pmovsxwd pmovzxwd pmovsxbq pmovzxbq pmovsxwq pmovzxwq pmovsxdq pmovzxdq mpsadbw |
| 94 | phminposuw ptest pcmpeqq packusdw |
| 95 | }, |
| 96 | # SSE4.2 |
| 97 | qw{ |
| 98 | pcmpestri pcmpestrm pcmpistri pcmpistrm pcmpgtq crc32 popcnt |
| 99 | } |
| 100 | ); |
| 101 | |
| 102 | # Undesired instructions for IA-32 architecture: Pentium 4 (SSE2) and newer. |
| 103 | # TODO: It would be much more reliable to list *allowed* instructions rather than list undesired |
| 104 | # instructions. In such a case the list will be stable and not require update when SSE5 is released. |
| 105 | my @ia32_bad_list = ( @sse2, @sse3, @ssse3, @sse4 ); |
| 106 | |
| 107 | my $ia32_bad_re = qr{@{[ "^(?:" . join( "|", @ia32_bad_list ) . ")" ]}}i; |
| 108 | |
| 109 | sub bad_ia32_instr($$) { |
| 110 | my ( $instr, $args ) = @_; |
| 111 | return ( defined( $instr ) and $instr =~ $ia32_bad_re ); |
| 112 | }; # sub bad_ia32_instr |
| 113 | |
| 114 | sub check_file($;$$) { |
| 115 | |
| 116 | my ( $file, $show_instructions, $max_instructions ) = @_; |
| 117 | my @bulk; |
| 118 | |
| 119 | if ( not defined( $max_instructions ) ) { |
| 120 | $max_instructions = 100; |
| 121 | }; # if |
| 122 | |
Andrey Churbanov | d315cea | 2015-01-16 12:54:51 +0000 | [diff] [blame] | 123 | execute( [ "x86_64-k1om-linux-objdump", "-d", $file ], -stdout => \@bulk ); |
Jim Cownie | 5e8470a | 2013-09-27 10:38:44 +0000 | [diff] [blame] | 124 | |
| 125 | my $n = 0; |
| 126 | my $errors = 0; |
Kazuaki Ishizaki | 4201679 | 2020-04-04 12:06:29 +0900 | [diff] [blame] | 127 | my $current_func = ""; # Name of current function. |
Jim Cownie | 5e8470a | 2013-09-27 10:38:44 +0000 | [diff] [blame] | 128 | my $reported_func = ""; # name of last reported function. |
| 129 | foreach my $line ( @bulk ) { |
| 130 | ++ $n; |
| 131 | if ( 0 ) { |
| 132 | } elsif ( $line =~ m{^\s*$} ) { |
| 133 | # Empty line. |
| 134 | # Ignore. |
| 135 | } elsif ( $line =~ m{^In archive (.*?):\s*$} ) { |
Jonathan Peyton | f0efbb5 | 2015-06-01 02:41:44 +0000 | [diff] [blame] | 136 | # In archive libomp.a: |
Jim Cownie | 5e8470a | 2013-09-27 10:38:44 +0000 | [diff] [blame] | 137 | } elsif ( $line =~ m{^(?:.*?):\s*file format (.*?)\s*$} ) { |
Jonathan Peyton | f0efbb5 | 2015-06-01 02:41:44 +0000 | [diff] [blame] | 138 | # libomp.so: file format elf64-x86-64-freebsd |
Jim Cownie | 5e8470a | 2013-09-27 10:38:44 +0000 | [diff] [blame] | 139 | # kmp_ftn_cdecl.o: file format elf64-x86-64 |
| 140 | my $fmt = $1; |
| 141 | if ( bad_fmt( $fmt ) ) { |
| 142 | runtime_error( "Invalid file format: $fmt." ); |
| 143 | }; # if |
| 144 | } elsif ( $line =~ m{^Disassembly of section (.*?):\s*$} ) { |
| 145 | # Disassembly of section .plt: |
| 146 | } elsif ( $line =~ m{^$hex+ <([^>]+)>:\s*$} ) { |
| 147 | # 0000000000017e98 <__kmp_str_format@plt-0x10>: |
| 148 | $current_func = $1; |
| 149 | } elsif ( $line =~ m{^\s*\.{3}\s*$} ) { |
| 150 | } elsif ( $line =~ m{^\s*($hex+):\s+($hex$hex(?: $hex$hex)*)\s+(?:lock\s+|rex[.a-z]*\s+)?([^ ]+)(?:\s+([^#]+?))?\s*(?:#|$)} ) { |
| 151 | # 17e98: ff 35 fa 7d 26 00 pushq 0x267dfa(%rip) # 27fc98 <_GLOBAL_OFFSET_TABLE> |
| 152 | my ( $addr, $dump, $instr, $args ) = ( $1, $2, $3, $4 ); |
| 153 | # Check this is not a bad instruction and xmm registers are not used. |
| 154 | if ( bad_instr( $instr, $args ) ) { |
| 155 | if ( $errors == 0 ) { |
| 156 | warning( "Invalid instructions found in `$file':" ); |
| 157 | }; # if |
| 158 | if ( $current_func ne $reported_func ) { |
| 159 | warning( " $current_func" ); |
| 160 | $reported_func = $current_func; |
| 161 | }; # if |
| 162 | ++ $errors; |
| 163 | if ( $show_instructions ) { |
| 164 | warning( " $line" ); |
| 165 | }; # if |
| 166 | if ( $errors >= $max_instructions ) { |
| 167 | info( "$errors invalid instructions found; scanning stopped." ); |
| 168 | last; |
| 169 | }; # if |
| 170 | }; # if |
| 171 | } else { |
| 172 | runtime_error( "Error parsing objdump output line $n:\n>>>> $line\n" ); |
| 173 | }; # if |
| 174 | }; # foreach $line |
| 175 | |
| 176 | return $errors; |
| 177 | |
| 178 | }; # sub check_file |
| 179 | |
| 180 | # -------------------------------------------------------------------------------------------------- |
| 181 | |
| 182 | # Parse command line. |
| 183 | my $max_instructions; |
| 184 | my $show_instructions; |
| 185 | get_options( |
Jonathan Peyton | 4c91ad1 | 2016-01-26 19:44:31 +0000 | [diff] [blame] | 186 | "os=s" => \$target_os, |
| 187 | "arch=s" => \$target_arch, |
| 188 | "mic-arch=s" => \$target_mic_arch, |
Jim Cownie | 5e8470a | 2013-09-27 10:38:44 +0000 | [diff] [blame] | 189 | "max-instructions=i" => \$max_instructions, |
| 190 | "show-instructions!" => \$show_instructions, |
Jim Cownie | 5e8470a | 2013-09-27 10:38:44 +0000 | [diff] [blame] | 191 | ); |
Jonathan Peyton | 4c91ad1 | 2016-01-26 19:44:31 +0000 | [diff] [blame] | 192 | my $target_platform = $target_os . "_" . $target_arch; |
Andrey Churbanov | d315cea | 2015-01-16 12:54:51 +0000 | [diff] [blame] | 193 | if ( "$target_os" eq "lin" and "$target_mic_arch" eq "knf" ) { |
| 194 | $mic_bad_re = qr{^(?:pause|[slm]fence|scatter|gather|cmpxchg16b|clevict[12])}i; |
Jim Cownie | 5e8470a | 2013-09-27 10:38:44 +0000 | [diff] [blame] | 195 | } else { |
Andrey Churbanov | d315cea | 2015-01-16 12:54:51 +0000 | [diff] [blame] | 196 | $mic_bad_re = qr{^(?:pause|[slm]fence|scatter|gather|cmov|cmpxchg16b|clevict[12])}i; |
Jim Cownie | 5e8470a | 2013-09-27 10:38:44 +0000 | [diff] [blame] | 197 | }; |
| 198 | if ( 0 ) { |
Jonathan Peyton | 4c91ad1 | 2016-01-26 19:44:31 +0000 | [diff] [blame] | 199 | } elsif ( $target_platform eq "lin_mic" ) { |
Andrey Churbanov | d315cea | 2015-01-16 12:54:51 +0000 | [diff] [blame] | 200 | *bad_instr = \*bad_mic_instr; |
| 201 | *bad_fmt = \*bad_mic_fmt; |
Jim Cownie | 5e8470a | 2013-09-27 10:38:44 +0000 | [diff] [blame] | 202 | } elsif ( $target_platform eq "lin_32" ) { |
| 203 | *bad_instr = \*bad_ia32_instr; |
| 204 | *bad_fmt = \*bad_ia32_fmt; |
| 205 | } else { |
Andrey Churbanov | d315cea | 2015-01-16 12:54:51 +0000 | [diff] [blame] | 206 | runtime_error( "Only works on lin_32 and lin_mic platforms." ); |
Jim Cownie | 5e8470a | 2013-09-27 10:38:44 +0000 | [diff] [blame] | 207 | }; # if |
| 208 | |
| 209 | # Do the work. |
| 210 | my $rc = 0; |
| 211 | if ( not @ARGV ) { |
| 212 | info( "No arguments specified -- nothing to do." ); |
| 213 | } else { |
| 214 | foreach my $arg ( @ARGV ) { |
| 215 | my $errs = check_file( $arg, $show_instructions, $max_instructions ); |
| 216 | if ( $errs > 0 ) { |
| 217 | $rc = 3; |
| 218 | }; # if |
| 219 | }; # foreach $arg |
| 220 | }; # if |
| 221 | |
| 222 | exit( $rc ); |
| 223 | |
| 224 | __END__ |
| 225 | |
| 226 | =pod |
| 227 | |
| 228 | =head1 NAME |
| 229 | |
| 230 | B<check-instruction-set.pl> -- Make sure binary file does not contain undesired instructions. |
| 231 | |
| 232 | =head1 SYNOPSIS |
| 233 | |
| 234 | B<check-instructions.pl> I<option>... I<file>... |
| 235 | |
| 236 | =head1 OPTIONS |
| 237 | |
| 238 | =over |
| 239 | |
| 240 | =item B<--architecture=>I<arch> |
| 241 | |
| 242 | Specify target architecture. |
| 243 | |
| 244 | =item B<--max-instructions=>I<number> |
| 245 | |
| 246 | Stop scanning if I<number> invalid instructions found. 100 by default. |
| 247 | |
| 248 | =item B<--os=>I<os> |
| 249 | |
| 250 | Specify target OS. |
| 251 | |
| 252 | =item B<-->[B<no->]B<show-instructions> |
| 253 | |
| 254 | Show invalid instructions found in the file. Bu default, instructions are not shown. |
| 255 | |
| 256 | =item Standard Options |
| 257 | |
| 258 | =over |
| 259 | |
| 260 | =item B<--doc> |
| 261 | |
| 262 | =item B<--manual> |
| 263 | |
| 264 | Print full help message and exit. |
| 265 | |
| 266 | =item B<--help> |
| 267 | |
| 268 | Print short help message and exit. |
| 269 | |
| 270 | =item B<--usage> |
| 271 | |
| 272 | Print very short usage message and exit. |
| 273 | |
| 274 | =item B<--verbose> |
| 275 | |
| 276 | Do print informational messages. |
| 277 | |
| 278 | =item B<--version> |
| 279 | |
| 280 | Print program version and exit. |
| 281 | |
| 282 | =item B<--quiet> |
| 283 | |
| 284 | Work quiet, do not print informational messages. |
| 285 | |
| 286 | =back |
| 287 | |
| 288 | =back |
| 289 | |
| 290 | =head1 ARGUMENTS |
| 291 | |
| 292 | =over |
| 293 | |
| 294 | =item I<file> |
| 295 | |
| 296 | File (object file or library, either static or dynamic) to check. |
| 297 | |
| 298 | =back |
| 299 | |
| 300 | =head1 DESCRIPTION |
| 301 | |
| 302 | The script runs F<objdump> utility to get disassembler listing and checks the file does not contain |
| 303 | unwanted instructions. |
| 304 | |
| 305 | Currently the script works only for: |
| 306 | |
| 307 | =over |
| 308 | |
Andrey Churbanov | d315cea | 2015-01-16 12:54:51 +0000 | [diff] [blame] | 309 | =item C<lin_mic> |
Jim Cownie | 5e8470a | 2013-09-27 10:38:44 +0000 | [diff] [blame] | 310 | |
| 311 | Intel(R) Many Integrated Core Architecture target OS. Undesired unstructions are: all x87 instructions and some others. |
| 312 | |
| 313 | =item C<lin_32> |
| 314 | |
| 315 | Undesired instructions are instructions not valid for Pentium 3 processor (SSE2 and newer). |
| 316 | |
| 317 | =back |
| 318 | |
| 319 | =cut |
| 320 | |