#!/usr/bin/perl -w use strict; # Tavis Ormandy 2003 # Improvments by Will Woods # Perl convertion by Georgi Georgiev # # Identify instruction set used in binary. # # initialize everything to zero. my ($i486,$i586,$ppro,$mmx,$sse,$sse2,$amd,$amd2,$cpuid) = (0,0,0,0,0,0,0,0,0); my ($vendor, $subarch); # unfortunately there are mnemonic collissions between vendor sets # so check vendor_id string, and enable relevant sets. print "Checking vendor_id string..."; my $param = shift; unless (defined $param and $param eq "--vendor") { open PIPE, "grep -Em1 '^vendor_id.*: ' /proc/cpuinfo | cut -d' ' -f2 | " or die; $_ = ; close PIPE; if (/GenuineIntel/) { $vendor="intel"; print "GenuineIntel\n" } elsif (/AuthenticAMD/) { $vendor="amd"; print "AuthenticAMD\n" } elsif (/CyrixInstead/) { $vendor="cyrix"; print "CyrixInstead\n" } elsif (/GenuineTMx86/) { $vendor="transmeta"; print "GenuineTMx86\n" } else { $vendor="other"; print "other\n" } } else { ($param,$vendor) = split /=/, $param; printf "%s\n", $vendor; $param = shift; } # quick sanity tests. defined $param or die "usage: $0 [--vendor=intel|amd|cyrix|transmeta] /path/to/binary\n"; -e $param or die "error: $param does not exist.\n"; -r $param or die "error: cant read $param.\n"; printf "Disassembling %s, please wait...\n", $param; # initialize screen output if ($vendor eq "intel") { printf "i486: %4u i586: %4u ppro: %4u mmx: %4u sse: %4u sse2: %4u\r", $i486, $i586, $ppro, $mmx, $sse, $sse2; } elsif ($vendor eq "amd") { printf "i486: %4u i586: %4u mmx: %4u sse: %4u 3dnow: %4u ext3dnow: %4u\r", $i486, $i586, $mmx, $sse, $amd, $amd2; } elsif ($vendor eq "cyrix") { printf "i486: %4u i586: %4u mmx: %4u\r", $i486, $i586, $mmx; } elsif ($vendor eq "transmeta") { printf "i486: %4u i586: %4u mmx: %4u\r", $i486, $i586, $mmx; } else { printf "i486: %4u i586: %4u ppro: %4u mmx: %4u sse: %4u sse2: %4u\r", $i486, $i586, $ppro, $mmx, $sse, $sse2; } # do the disassembling. open PIPE, "objdump -d $param | cut -f3 | cut -d' ' -f1 |" or die; my $print; while (defined (my $instruction = )) { chomp $instruction; if (scalar (grep /^$instruction$/, "cmpxchg","xadd","bswap","invd","wbinvd","invlpg")) { $i486++; $print=1 } elsif (grep /^$instruction$/, "rdmsr","wrmsr","rdtsc","cmpxch8B","rsm") { $i586++; $print=1 } elsif (grep /^$instruction$/, "cmovcc","fcmovcc","fcomi","fcomip","fucomi","fucomip","rdpmc","ud2") { $ppro++; $print=1 } elsif (grep /^$instruction$/, "emms","movd","movq","packsswb","packssdw","packuswb","paddb","paddw","paddd","paddsb","paddsw","paddusb","paddusw","pand","pandn","pcmpeqb","pcmpeqw","pcmpeqd","pcmpgtb","pcmpgtw","pcmpgtd","pmaddwd","pmulhw","pmullw","por","psllw","pslld","psllq","psraw","psrad","psrlw","psrld","psrlq","psubb","psubw","psubd","psubsb","psubsw","psubusb","psubusw","punpckhbw","punpckhwd","punpckhdq","punpcklbw","punpcklwd","punpckldq","pxor") { $mmx++; $print=1} elsif (grep /^$instruction$/, "addps","addss","andnps","andps","cmpps","cmpss","comiss","cvtpi2ps","cvtps2pi","cvtsi2ss","cvtss2si","cvttps2pi","cvttss2si","divps","divss","fxrstor","fxsave","ldmxcsr","maxps","maxss","minps","minss","movaps","movhlps","movhps","movlhps","movlps","movmskps","movss","movups","mulps","mulss","orps","pavgb","pavgw","psadbw","rcpps","rcpss","rsqrtps","rsqrtss","shufps","sqrtps","sqrtss","stmxcsr","subps","subss","ucomiss","unpckhps","unpcklps","xorps","pextrw","pinsrw","pmaxsw","pmaxub","pminsw","pminub","pmovmskb","pmulhuw","pshufw","maskmovq","movntps","movntq","prefetch","sfence") { $sse++; $print=1 } elsif (grep /^$instruction$/, "addpd","addsd","andnpd","andpd","clflush","cmppd","cmpsd","comisd","cvtdq2pd","cvtdq2ps","cvtpd2pi","cvtpd2pq","cvtpd2ps","cvtpi2pd","cvtps2dq","cvtps2pd","cvtsd2si","cvtsd2ss","cvtsi2sd","cvtss2sd","cvttpd2pi","cvttpd2dq","cvttps2dq","cvttsd2si","divpd","divsd","lfence","maskmovdqu","maxpd","maxsd","mfence","minpd","minsd","movapd","movd","movdq2q","movdqa","movdqu","movhpd","movlpd","movmskpd","movntdq","movnti","movntpd","movq","movq2dq","movsd","movupd","mulpd","mulsd","orpd","packsswb","packssdw","packuswb","paddb","paddw","paddd","paddq","paddq","paddsb","paddsw","paddusb","paddusw","pand","pandn","pause","pavgb","pavgw","pcmpeqb","pcmpeqw","pcmpeqd","pcmpgtb","pcmpgtw","pcmpgtd","pextrw","pinsrw","pmaddwd","pmaxsw","pmaxub","pminsw","pminub","pmovmskb","pmulhw","pmulhuw","pmullw","pmuludq","pmuludq","por","psadbw","pshufd","pshufhw","pshuflw","pslldq","psllw","pslld","psllq","psraw","psrad","psrldq","psrlw","psrld","psrlq","psubb","psubw","psubd","psubq","psubq","psubsb","psubsw","psubusb","psubusw","psubsb","punpckhbw","punpckhwd","punpckhdq","punpckhqdq","punpcklbw","punpcklwd","punpckldq","punpcklqdq","pxor","shufpd","sqrtpd","sqrtsd","subpd","subsd","ucomisd","unpckhpd","unpcklpd","xorpd") { $sse2++; $print=1 } elsif (grep /^$instruction$/, "pavgusb","pfadd","pfsub","pfsubr","pfacc","pfcmpge","pfcmpgt","pfcmpeq","pfmin","pfmax","pi2fw","pi2fd","pf2iw","pf2id","pfrcp","pfrsqrt","pfmul","pfrcpit1","pfrsqit1","pfrcpit2","pmulhrw","pswapw","femms","prefetch") { $amd++; $print=1 } elsif (grep /^$instruction$/, "pf2iw","pfnacc","pfpnacc","pi2fw","pswapd","maskmovq","movntq","pavgb","pavgw","pextrw","pinsrw","pmaxsw","pmaxub","pminsw","pminub","pmovmskb","pmulhuw","prefetchnta","prefetcht0","prefetcht1","prefetcht2","psadbw","pshufw","sfence") { $amd2++; $print=1 } elsif (grep /^$instruction$/, "cpuid") {$cpuid++, $i586++; $print=1 } if ($print) { if ($vendor eq "intel") { printf "i486: %4u i586: %4u ppro: %4u mmx: %4u sse: %4u sse2: %4u\r", $i486, $i586, $ppro, $mmx, $sse, $sse2; } elsif ($vendor eq "amd") { printf "i486: %4u i586: %4u mmx: %4u sse: %4u 3dnow: %4u ext3dnow: %4u\r", $i486, $i586, $mmx, $sse, $amd, $amd2; } elsif ($vendor eq "cyrix") { printf "i486: %4u i586: %4u mmx: %4u\r", $i486, $i586, $mmx; } elsif ($vendor eq "transmeta") { printf "i486: %4u i586: %4u mmx: %4u\r", $i486, $i586, $mmx; } else { printf "i486: %4u i586: %4u ppro: %4u mmx: %4u sse: %4u sse2: %4u\r", $i486, $i586, $ppro, $mmx, $sse, $sse2; } undef $print; } } # print a newline print "\n"; # cpuid instruction could mean the application checks to see # if an instruction is supported before executing it. This might # mean it will work on anything over a pentium. if ($cpuid) { printf "\nThis binary was found to contain the cpuid instruction.\n"; printf "It may be able to conditionally execute instructions if\n"; printf "they are supported on the host (i586+).\n\n"; } # print minimum required processor, if there are collissions # use the vendor to decide what to print. if ($sse2) { $subarch="Pentium IV (pentium4)" } elsif ($sse) { if ($vendor eq "intel") { $subarch="Pentium III (pentium3)" } elsif ($vendor eq "amd") { $subarch="AMD Athlon 4 (athlon-4)" } else { $subarch="Pentium III (pentium3)" } } elsif ($vendor eq "amd" and $amd2) { $subarch="AMD Athlon (athlon)" } elsif ($vendor eq "amd" and $amd) { $subarch="AMD K6 III (k6-3)" } elsif ($mmx) { if ($vendor eq "intel") { if ($ppro) { $subarch="Pentium II (pentium2)" } else { $subarch="Intel Pentium MMX [P55C] (pentium-mmx)" } } elsif ($vendor eq "amd") { $subarch="AMD K6 (k6)" } elsif ($vendor eq "cyrix") { $subarch="Cyrix 6x86MX / MII (pentium-mmx)" } else { $subarch="Intel Pentium MMX [P55C] (pentium-mmx)" } } elsif ($ppro) { $subarch="Pentium Pro (i686 or pentiumpro)" } elsif ($i586) { $subarch="Pentium or compatible (i586) (i586 or pentium)" } elsif ($i486) { $subarch="80486 or comaptible (i486)" } else { $subarch="80386 or compatible (i386)" } # print message and exit. printf "%s will run on %s or higher processor.\n", $param, $subarch;