github.com/aergoio/aergo@v1.3.1/libtool/src/gmp-6.1.2/mpn/x86/k6/cross.pl (about)

     1  #! /usr/bin/perl
     2  
     3  # Copyright 2000, 2001 Free Software Foundation, Inc.
     4  #
     5  #  This file is part of the GNU MP Library.
     6  #
     7  #  The GNU MP Library is free software; you can redistribute it and/or modify
     8  #  it under the terms of either:
     9  #
    10  #    * the GNU Lesser General Public License as published by the Free
    11  #      Software Foundation; either version 3 of the License, or (at your
    12  #      option) any later version.
    13  #
    14  #  or
    15  #
    16  #    * the GNU General Public License as published by the Free Software
    17  #      Foundation; either version 2 of the License, or (at your option) any
    18  #      later version.
    19  #
    20  #  or both in parallel, as here.
    21  #
    22  #  The GNU MP Library is distributed in the hope that it will be useful, but
    23  #  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    24  #  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    25  #  for more details.
    26  #
    27  #  You should have received copies of the GNU General Public License and the
    28  #  GNU Lesser General Public License along with the GNU MP Library.  If not,
    29  #  see https://www.gnu.org/licenses/.
    30  
    31  
    32  # Usage: cross.pl [filename.o]...
    33  #
    34  # Produce an annotated disassembly of the given object files, indicating
    35  # certain code alignment and addressing mode problems afflicting K6 chips.
    36  # "ZZ" is used on all annotations, so this can be searched for.
    37  #
    38  # With no arguments, all .o files corresponding to .asm files are processed.
    39  # This is good in the mpn object directory of a k6*-*-* build.
    40  #
    41  # Code alignments of 8 bytes or more are handled.  When 32 is used, cache
    42  # line boundaries will fall in at offsets 0x20,0x40,etc and problems are
    43  # flagged at those locations.  When 16 is used, the line boundaries can also
    44  # fall at offsets 0x10,0x30,0x50,etc, depending where the file is loaded, so
    45  # problems are identified there too.  Likewise when 8 byte alignment is used
    46  # problems are flagged additionally at 0x08,0x18,0x28,etc.
    47  #
    48  # Usually 32 byte alignment is used for k6 routines, but less is certainly
    49  # possible if through good luck, or a little tweaking, cache line crossing
    50  # problems can be avoided at the extra locations.
    51  #
    52  # Bugs:
    53  #
    54  # Instructions without mod/rm bytes or which are already vector decoded are
    55  # unaffected by cache line boundary crossing, but not all of these have yet
    56  # been put in as exceptions.  All that occur in practice in GMP are present
    57  # though.
    58  #
    59  # There's no messages for using the vector decoded addressing mode (%esi),
    60  # but that's easy to avoid when coding.
    61  #
    62  # Future:
    63  #
    64  # Warn about jump targets that are poorly aligned (less than 2 instructions
    65  # before a cache line boundary).
    66  
    67  use strict;
    68  
    69  sub disassemble {
    70      my ($file) = @_;
    71      my ($addr,$b1,$b2,$b3, $prefix,$opcode,$modrm);
    72      my $align;
    73  
    74      open (IN, "objdump -Srfh $file |")
    75  	|| die "Cannot open pipe from objdump\n";
    76      while (<IN>) {
    77  	print;
    78  
    79  	if (/^[ \t]*[0-9]+[ \t]+\.text[ \t]/ && /2\*\*([0-9]+)$/) {
    80  	    $align = 1 << $1;
    81  	    if ($align < 8) {
    82  		print "ZZ cross.pl cannot handle alignment < 2**3\n";
    83  		$align = 8
    84  	    }
    85  	}
    86  
    87  	if (/^[ \t]*([0-9a-f]*):[ \t]*([0-9a-f]+)[ \t]+([0-9a-f]+)[ \t]+([0-9a-f]+)/) {
    88  	    ($addr,$b1,$b2,$b3) = ($1,$2,$3,$4);
    89  
    90  	} elsif (/^[ \t]*([0-9a-f]*):[ \t]*([0-9a-f]+)[ \t]+([0-9a-f]+)/) {
    91  	    ($addr,$b1,$b2,$b3) = ($1,$2,$3,'');
    92  
    93  	} elsif (/^[ \t]*([0-9a-f]*):[ \t]*([0-9a-f]+)/) {
    94  	    ($addr,$b1,$b2,$b3) = ($1,$2,'','');
    95  
    96  	} else {
    97  	    next;
    98  	}
    99  
   100  	if ($b1 =~ /0f/) {
   101  	    $prefix = $b1;
   102  	    $opcode = $b2;
   103  	    $modrm = $b3;
   104  	} else {
   105  	    $prefix = '';
   106  	    $opcode = $b1;
   107  	    $modrm = $b2;
   108  	}
   109  
   110  	# modrm of the form 00-xxx-100 with an 0F prefix is the problem case
   111  	# for K6 and pre-CXT K6-2
   112  	if ($prefix =~ /0f/
   113  	    && $opcode !~ /^8/         # jcond disp32
   114  	    && $modrm =~ /^[0-3][4c]/) {
   115  	    print "ZZ ($file) >3 bytes to determine instruction length [K6]\n";
   116  	}
   117  
   118  	# with just an opcode, starting 1f mod 20h
   119  	if (($align==32 && $addr =~ /[13579bdf]f$/
   120  	     || $align==16 && $addr =~ /f$/
   121  	     || $align==8 && $addr =~ /[7f]$/)
   122  	    && $prefix !~ /0f/
   123  	    && $opcode !~ /1[012345]/ # adc
   124  	    && $opcode !~ /1[89abcd]/ # sbb
   125  	    && $opcode !~ /^4/        # inc/dec reg
   126  	    && $opcode !~ /^5/        # push/pop reg
   127  	    && $opcode !~ /68/        # push $imm32
   128  	    && $opcode !~ /^7/        # jcond disp8
   129  	    && $opcode !~ /a[89]/     # test+imm
   130  	    && $opcode !~ /a[a-f]/    # stos/lods/scas
   131  	    && $opcode !~ /b8/        # movl $imm32,%eax
   132  	    && $opcode !~ /d[0123]/   # rcl
   133  	    && $opcode !~ /e[0123]/   # loop/loopz/loopnz/jcxz
   134  	    && $opcode !~ /e8/        # call disp32
   135  	    && $opcode !~ /e[9b]/     # jmp disp32/disp8
   136  	    && $opcode !~ /f[89abcd]/ # clc,stc,cli,sti,cld,std
   137  	    && !($opcode =~ /f[67]/          # grp 1
   138  		 && $modrm =~ /^[2367abef]/) # mul, imul, div, idiv
   139  	    && $modrm !~ /^$/) {
   140  	    print "ZZ ($file) opcode/modrm cross 32-byte boundary\n";
   141  	}
   142  
   143  	# with an 0F prefix, anything starting at 1f mod 20h
   144  	if (($align==32 && $addr =~ /[13579bdf][f]$/
   145  	     || $align==16 && $addr =~ /f$/
   146  	     || $align==8 && $addr =~ /[7f]$/)
   147  	    && $prefix =~ /0f/
   148  	    && $opcode !~ /af/        # imul
   149  	    && $opcode !~ /a[45]/     # shldl
   150  	    && $opcode !~ /a[cd]/     # shrdl
   151  	    ) {
   152  	    print "ZZ ($file) prefix/opcode cross 32-byte boundary\n";
   153  	}
   154  
   155  	# with an 0F prefix, anything with mod/rm starting at 1e mod 20h
   156  	if (($align==32 && $addr =~ /[13579bdf][e]$/
   157  	     || $align==16 && $addr =~ /[e]$/
   158  	     || $align==8 && $addr =~ /[6e]$/)
   159  	    && $prefix =~ /0f/
   160  	     && $opcode !~ /^8/        # jcond disp32
   161  	     && $opcode !~ /af/        # imull reg,reg
   162  	     && $opcode !~ /a[45]/     # shldl
   163  	     && $opcode !~ /a[cd]/     # shrdl
   164  	    && $modrm !~ /^$/) {
   165  	    print "ZZ ($file) prefix/opcode/modrm cross 32-byte boundary\n";
   166  	}
   167      }
   168      close IN || die "Error from objdump (or objdump not available)\n";
   169  }
   170  
   171  
   172  my @files;
   173  if ($#ARGV >= 0) {
   174      @files = @ARGV;
   175  } else {
   176      @files = glob "*.asm";
   177      map {s/.asm/.o/} @files;
   178  }
   179  
   180  foreach (@files)  {
   181      disassemble($_);
   182  }