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