155714Skris#! /usr/bin/perl 255714Skris 355714Skris# Copyright 2000, 2001 Free Software Foundation, Inc. 455714Skris# 555714Skris# This file is part of the GNU MP Library. 655714Skris# 755714Skris# The GNU MP Library is free software; you can redistribute it and/or modify 8280304Sjkim# it under the terms of either: 955714Skris# 1055714Skris# * the GNU Lesser General Public License as published by the Free 1155714Skris# Software Foundation; either version 3 of the License, or (at your 1255714Skris# option) any later version. 1355714Skris# 1455714Skris# or 15280304Sjkim# 1655714Skris# * the GNU General Public License as published by the Free Software 1755714Skris# Foundation; either version 2 of the License, or (at your option) any 1855714Skris# later version. 1955714Skris# 2055714Skris# or both in parallel, as here. 2155714Skris# 22280304Sjkim# The GNU MP Library is distributed in the hope that it will be useful, but 2355714Skris# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 2455714Skris# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 2555714Skris# for more details. 2655714Skris# 2755714Skris# You should have received copies of the GNU General Public License and the 2855714Skris# GNU Lesser General Public License along with the GNU MP Library. If not, 2955714Skris# see https://www.gnu.org/licenses/. 3055714Skris 3155714Skris 3255714Skris# Usage: cross.pl [filename.o]... 3355714Skris# 3455714Skris# Produce an annotated disassembly of the given object files, indicating 3555714Skris# certain code alignment and addressing mode problems afflicting K6 chips. 3655714Skris# "ZZ" is used on all annotations, so this can be searched for. 37280304Sjkim# 3855714Skris# With no arguments, all .o files corresponding to .asm files are processed. 3955714Skris# This is good in the mpn object directory of a k6*-*-* build. 40280304Sjkim# 4155714Skris# Code alignments of 8 bytes or more are handled. When 32 is used, cache 4255714Skris# line boundaries will fall in at offsets 0x20,0x40,etc and problems are 4355714Skris# flagged at those locations. When 16 is used, the line boundaries can also 4455714Skris# fall at offsets 0x10,0x30,0x50,etc, depending where the file is loaded, so 4555714Skris# problems are identified there too. Likewise when 8 byte alignment is used 4655714Skris# problems are flagged additionally at 0x08,0x18,0x28,etc. 4755714Skris# 4855714Skris# Usually 32 byte alignment is used for k6 routines, but less is certainly 4955714Skris# possible if through good luck, or a little tweaking, cache line crossing 5055714Skris# problems can be avoided at the extra locations. 5155714Skris# 52280304Sjkim# Bugs: 5355714Skris# 5455714Skris# Instructions without mod/rm bytes or which are already vector decoded are 5555714Skris# unaffected by cache line boundary crossing, but not all of these have yet 5655714Skris# been put in as exceptions. All that occur in practice in GMP are present 5755714Skris# though. 5855714Skris# 59280304Sjkim# There's no messages for using the vector decoded addressing mode (%esi), 60280304Sjkim# but that's easy to avoid when coding. 61280304Sjkim# 62280304Sjkim# Future: 63160814Ssimon# 64280304Sjkim# Warn about jump targets that are poorly aligned (less than 2 instructions 65160814Ssimon# before a cache line boundary). 66160814Ssimon 6755714Skrisuse strict; 6855714Skris 6955714Skrissub disassemble { 7055714Skris my ($file) = @_; 71109998Smarkm my ($addr,$b1,$b2,$b3, $prefix,$opcode,$modrm); 72280304Sjkim my $align; 7355714Skris 7455714Skris open (IN, "objdump -Srfh $file |") 7555714Skris || die "Cannot open pipe from objdump\n"; 7655714Skris while (<IN>) { 7755714Skris print; 7855714Skris 7955714Skris if (/^[ \t]*[0-9]+[ \t]+\.text[ \t]/ && /2\*\*([0-9]+)$/) { 8055714Skris $align = 1 << $1; 8155714Skris if ($align < 8) { 8255714Skris print "ZZ cross.pl cannot handle alignment < 2**3\n"; 8355714Skris $align = 8 84160814Ssimon } 85160814Ssimon } 86280304Sjkim 87160814Ssimon if (/^[ \t]*([0-9a-f]*):[ \t]*([0-9a-f]+)[ \t]+([0-9a-f]+)[ \t]+([0-9a-f]+)/) { 88160814Ssimon ($addr,$b1,$b2,$b3) = ($1,$2,$3,$4); 89280304Sjkim 90160814Ssimon } elsif (/^[ \t]*([0-9a-f]*):[ \t]*([0-9a-f]+)[ \t]+([0-9a-f]+)/) { 9155714Skris ($addr,$b1,$b2,$b3) = ($1,$2,$3,''); 92280304Sjkim 9355714Skris } elsif (/^[ \t]*([0-9a-f]*):[ \t]*([0-9a-f]+)/) { 94280304Sjkim ($addr,$b1,$b2,$b3) = ($1,$2,'',''); 95280304Sjkim 96280304Sjkim } else { 97280304Sjkim next; 98280304Sjkim } 99280304Sjkim 100280304Sjkim if ($b1 =~ /0f/) { 101280304Sjkim $prefix = $b1; 102280304Sjkim $opcode = $b2; 10355714Skris $modrm = $b3; 104280304Sjkim } else { 105280304Sjkim $prefix = ''; 10655714Skris $opcode = $b1; 10755714Skris $modrm = $b2; 108280304Sjkim } 10955714Skris 110280304Sjkim # modrm of the form 00-xxx-100 with an 0F prefix is the problem case 111280304Sjkim # for K6 and pre-CXT K6-2 11255714Skris if ($prefix =~ /0f/ 113280304Sjkim && $opcode !~ /^8/ # jcond disp32 114280304Sjkim && $modrm =~ /^[0-3][4c]/) { 115280304Sjkim print "ZZ ($file) >3 bytes to determine instruction length [K6]\n"; 116280304Sjkim } 117280304Sjkim 118280304Sjkim # with just an opcode, starting 1f mod 20h 119280304Sjkim if (($align==32 && $addr =~ /[13579bdf]f$/ 120280304Sjkim || $align==16 && $addr =~ /f$/ 121280304Sjkim || $align==8 && $addr =~ /[7f]$/) 12268651Skris && $prefix !~ /0f/ 123280304Sjkim && $opcode !~ /1[012345]/ # adc 124280304Sjkim && $opcode !~ /1[89abcd]/ # sbb 125280304Sjkim && $opcode !~ /^4/ # inc/dec reg 126280304Sjkim && $opcode !~ /^5/ # push/pop reg 127280304Sjkim && $opcode !~ /68/ # push $imm32 128280304Sjkim && $opcode !~ /^7/ # jcond disp8 12955714Skris && $opcode !~ /a[89]/ # test+imm 13055714Skris && $opcode !~ /a[a-f]/ # stos/lods/scas 131280304Sjkim && $opcode !~ /b8/ # movl $imm32,%eax 132280304Sjkim && $opcode !~ /d[0123]/ # rcl 133160814Ssimon && $opcode !~ /e[0123]/ # loop/loopz/loopnz/jcxz 134280304Sjkim && $opcode !~ /e8/ # call disp32 13559191Skris && $opcode !~ /e[9b]/ # jmp disp32/disp8 136280304Sjkim && $opcode !~ /f[89abcd]/ # clc,stc,cli,sti,cld,std 137280304Sjkim && !($opcode =~ /f[67]/ # grp 1 138280304Sjkim && $modrm =~ /^[2367abef]/) # mul, imul, div, idiv 13959191Skris && $modrm !~ /^$/) { 140280304Sjkim print "ZZ ($file) opcode/modrm cross 32-byte boundary\n"; 141280304Sjkim } 142160814Ssimon 143280304Sjkim # with an 0F prefix, anything starting at 1f mod 20h 144280304Sjkim if (($align==32 && $addr =~ /[13579bdf][f]$/ 145280304Sjkim || $align==16 && $addr =~ /f$/ 146280304Sjkim || $align==8 && $addr =~ /[7f]$/) 147280304Sjkim && $prefix =~ /0f/ 148238405Sjkim && $opcode !~ /af/ # imul 149280304Sjkim && $opcode !~ /a[45]/ # shldl 150160814Ssimon && $opcode !~ /a[cd]/ # shrdl 151280304Sjkim ) { 152280304Sjkim print "ZZ ($file) prefix/opcode cross 32-byte boundary\n"; 153280304Sjkim } 15455714Skris 155280304Sjkim # with an 0F prefix, anything with mod/rm starting at 1e mod 20h 15655714Skris if (($align==32 && $addr =~ /[13579bdf][e]$/ 157280304Sjkim || $align==16 && $addr =~ /[e]$/ 158280304Sjkim || $align==8 && $addr =~ /[6e]$/) 15955714Skris && $prefix =~ /0f/ 16059191Skris && $opcode !~ /^8/ # jcond disp32 16159191Skris && $opcode !~ /af/ # imull reg,reg 16255714Skris && $opcode !~ /a[45]/ # shldl 163280304Sjkim && $opcode !~ /a[cd]/ # shrdl 164280304Sjkim && $modrm !~ /^$/) { 165280304Sjkim print "ZZ ($file) prefix/opcode/modrm cross 32-byte boundary\n"; 166280304Sjkim } 167280304Sjkim } 168280304Sjkim close IN || die "Error from objdump (or objdump not available)\n"; 169280304Sjkim} 170280304Sjkim 171280304Sjkim 172280304Sjkimmy @files; 173280304Sjkimif ($#ARGV >= 0) { 174280304Sjkim @files = @ARGV; 175280304Sjkim} else { 176280304Sjkim @files = glob "*.asm"; 177280304Sjkim map {s/.asm/.o/} @files; 178280304Sjkim} 179280304Sjkim 180280304Sjkimforeach (@files) { 181280304Sjkim disassemble($_); 182111147Snectar} 183280304Sjkim