Home | History | Annotate | Download | only in bfd
      1 #!/usr/bin/perl
      2 # -*- perl -*-
      3 #
      4 # Toshiba MeP Media Engine Relocation Generator
      5 # Copyright (C) 2001-2016 Free Software Foundation, Inc.
      6 # This file is part of BFD.
      7 # Originally written by DJ Delorie <dj (at] redhat.com>
      8 #
      9 # This program is free software; you can redistribute it and/or modify
     10 # it under the terms of the GNU General Public License as published by
     11 # the Free Software Foundation; either version 3 of the License, or
     12 # (at your option) any later version.
     13 #
     14 # This program is distributed in the hope that it will be useful,
     15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
     16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17 # GNU General Public License for more details.
     18 #
     19 # You should have received a copy of the GNU General Public License
     20 # along with this program; if not, write to the Free Software
     21 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
     22 # MA 02110-1301, USA.
     23 
     24 
     25 # Usage: Run this anywhere inside your source tree.  It will read
     26 # include/elf/mep.h and scan the comments therein.  It will renumber
     27 # the relocs to be sequential (this is needed so that bfd/elf32-mep.h
     28 # works) if needed.  It will then update the reloc list in bfd/reloc.c
     29 # and the howto, mapping, and apply routines in bfd/elf32-mep.c.  You
     30 # can then regenerate bfd-in2.h and check everything in.
     31 
     32 # FIXME: After the relocation list is finalized, change this to
     33 # *verify* the reloc list, rather than resequence it.
     34 
     35 while (! -f "include/elf/mep.h" && ! -f "bfd/reloc.c") {
     36     chdir "..";
     37     $pwd = `pwd`;
     38     if ($pwd !~ m@/.*/@) {
     39 	print STDERR "Cannot find include/elf/mep.h or bfd/reloc.h\n";
     40 	exit 1;
     41     }
     42 }
     43 $pwd = `pwd`;
     44 print "srctop is $pwd";
     45 
     46 printf "Reading include/elf/mep.h ...\n";
     47 open(MEPH, "include/elf/mep.h");
     48 open(MEPHO, "> include/elf/mep.h.new") || die("mep.h.new create: $!");
     49 $val = 0;
     50 while (<MEPH>) {
     51     if (($pre,$rel,$rest) = /(.*RELOC_NUMBER \()([^,]+), *\d+(.*)/) {
     52 	$rest =~ s/[\r\n]+$//;
     53 	print (MEPHO "$pre$rel, $val$rest\n") || die("mep.h.new write: $!");
     54 	$val ++;
     55 	$rel =~ s/R_MEP_//;
     56 	push(@relocs, $rel);
     57 
     58 	$rest =~ s@.*/\* @@;
     59 	($pattern, $sign, $attrs) = $rest =~ m@(.*) ([US]) (.*)\*/@;
     60 	$pattern =~ s/ //g;
     61 	push(@pattern, $pattern);
     62 	push(@sign, $sign);
     63 	push(@attrs, $attrs);
     64 
     65 	printf "%4d $rel p=`$pattern' s=`$sign' a=`$attrs'\n", $#pattern;
     66 
     67     } else {
     68 	print(MEPHO) || die("mep.h.new write: $!");
     69     }
     70 }
     71 close(MEPH);
     72 close(MEPHO) || die("mep.h.new close: $!");
     73 
     74 &swapfile("include/elf/mep.h");
     75 
     76 redo_file ("bfd/reloc.c",
     77 	   "",
     78 	   "ENUMDOC\n  Toshiba Media Processor Relocations.\n\nCOMMENT\n",
     79 	   "ENUM\n  BFD_RELOC_MEP_%s\n",
     80 	   "");
     81 
     82 $autogen = "    /* This section generated from bfd/mep-relocs.pl from include/elf/mep.h.  */\n";
     83 
     84 redo_file ("bfd/elf32-mep.c",
     85 	   "MEPRELOC:HOWTO",
     86 	   $autogen,
     87 	   "MEPRELOC:END",
     88 	   "",
     89 	   "&emit_howto();",
     90 	   "MEPRELOC:MAP",
     91 	   $autogen,
     92 	   "MEPRELOC:END",
     93 	   "",
     94 	   "    MAP(%s);\n",
     95 	   "MEPRELOC:APPLY",
     96 	   $autogen,
     97 	   "MEPRELOC:END",
     98 	   "",
     99 	   "&emit_apply();",
    100 	   );
    101 
    102 sub mask2shifts {
    103     my ($mask) = @_;
    104     my ($bits, $left, $right, $ci, $c, $cv);
    105     $bits = 0;
    106     $left = 0;
    107     $right = 32;
    108     for ($ci=0; $ci<length($mask); $ci++) {
    109 	$c = substr($mask, $ci, 1);
    110 	$left++;
    111 	next if $c eq '-';
    112 	$left = 0;
    113 	$cv = ord($c) - ord('0');
    114 	$cv -= ord('a') - ord('9') - 1 if $cv > 9;
    115 	$right = $cv unless $right < $cv;
    116 	$bits = $cv+1 unless $bits > $cv+1;
    117     }
    118     $mask =~ tr/-/1/c;
    119     $mask =~ tr/-/0/;
    120     ($rmask = $mask) =~ tr/01/10/;
    121     $mask = unpack("H*", pack("B*", $mask));
    122     $rmask = unpack("H*", pack("B*", $rmask));
    123     return ($bits, $left, $right, $mask, $rmask);
    124 }
    125 
    126 sub emit_howto {
    127     for ($i=2; $i<=$#relocs; $i++) {
    128 	$mask = $pattern[$i];
    129 
    130 	if (length($mask) == 8)     { $bytesize = 0; }
    131 	elsif (length($mask) == 16) { $bytesize = 1; }
    132 	elsif (length($mask) == 32) { $bytesize = 2; }
    133 
    134 	($bits, $left, $right, $mask) = mask2shifts ($mask);
    135 	$bits[$i] = $bits;
    136 	$pcrel = 0;
    137 	$pcrel = 1 if $attrs[$i] =~ /pc-rel/i;
    138 	$overflow = $sign[$i];
    139 	$overflow = 'N' if $attrs[$i] =~ /no-overflow/;
    140 
    141 	$c = "$relocs[$i],";
    142 	printf(NEW "  MEPREL (R_MEP_%-10s%d,%3d,%2d,%2d,%2d,%2s, 0x%s),\n",
    143 	       $c, $bytesize, $bits, $left, $right, $pcrel, $overflow, $mask);
    144     }
    145 }
    146 
    147 sub emit_apply {
    148     for ($i=2; $i<=$#relocs; $i++) {
    149 	$v = "u";
    150 	$v = "s" if $sign[$i] =~ /S/;
    151 	if (length($pattern[$i]) == 8) {
    152 	    $e = ''; # no endian swap for bytes
    153 	} elsif ($pattern[$i] =~ /-/ || length($pattern[$i]) == 16) {
    154 	    $e = '^e2'; # endian swap - 2byte words only
    155 	} else {
    156 	    $e = '^e4' # endian swap for data
    157 	}
    158 	print NEW "    case R_MEP_$relocs[$i]: /* $pattern[$i] */\n";
    159 	if ($attrs[$i] =~ /tp-rel/i) {
    160 	    print NEW "      $v -= mep_tpoff_base(rel->r_offset);\n";
    161 	}
    162 	if ($attrs[$i] =~ /gp-rel/i) {
    163 	    print NEW "      $v -= mep_sdaoff_base(rel->r_offset);\n";
    164 	}
    165 	if ($attrs[$i] !~ /no-overflow/ && $bits[$i] < 32) {
    166 	    if ($v eq "u") {
    167 		$max = (1 << $bits[$i]) - 1;
    168 		print NEW "      if (u > $max) r = bfd_reloc_overflow;\n";
    169 	    } else {
    170 		$min = -(1 << ($bits[$i]-1));
    171 		$max = (1 << ($bits[$i]-1)) - 1;
    172 		print NEW "      if ($min > s || s > $max) r = bfd_reloc_overflow;\n";
    173 	    }
    174 	}
    175 	for ($b=0; $b<length($pattern[$i]); $b += 8) {
    176 	    $mask = substr($pattern[$i], $b, 8);
    177 	    ($bits, $left, $right, $mask, $rmask) = mask2shifts ($mask);
    178 	    if ($left > $right) { $left -= $right; $right = 0; }
    179 	    else { $right -= $left; $left = 0; }
    180 
    181 	    if ($mask ne "00") {
    182 		$bb = $b / 8;
    183 		print NEW "      byte[$bb$e] = ";
    184 		print NEW "(byte[$bb$e] & 0x$rmask) | " if $rmask ne "00";
    185 		if ($left) {
    186 		    print NEW "(($v << $left) & 0x$mask)";
    187 		} elsif ($right) {
    188 		    print NEW "(($v >> $right) & 0x$mask)";
    189 		} else {
    190 		    print NEW "($v & 0x$mask)";
    191 		}
    192 		print NEW ";\n";
    193 	    }
    194 	}
    195 	print NEW "      break;\n";
    196     }
    197 }
    198 
    199 
    200 #-----------------------------------------------------------------------------
    201 
    202 sub redo_file {
    203     my ($file, @control) = @_;
    204     open(OLD, $file);
    205     open(NEW, "> $file.new") || die("$file.new create: $!");
    206 
    207     print "Scanning file $file ...\n";
    208 
    209     while (1) {
    210 	$start = shift @control;
    211 	$prefix = shift @control;
    212 	$end = shift @control;
    213 	$suffix = shift @control;
    214 	$pattern = shift @control;
    215 
    216 	if (!$start) {
    217 	    print NEW while <OLD>;
    218 	    last;
    219 	}
    220 
    221 	print "  looking for $start\n";
    222 	while (<OLD>) {
    223 	    print NEW;
    224 	    last if /\Q$start\E/;
    225 	}
    226 	print "can't find $start\n" unless $_;
    227 	last unless $_;
    228 
    229 	print NEW $prefix;
    230 	if ($pattern =~ /^\&/) {
    231 	    eval $pattern;
    232 	    die("$pattern: $@") if $@;
    233 	} else {
    234 	    for $i (2..$#relocs) {
    235 		printf (NEW "$pattern", $relocs[$i]) || die("$file.new write: $!");
    236 		$pattern =~ s/^ENUM\n/ENUMX\n/;
    237 	    }
    238 	}
    239 	print NEW $suffix;
    240 	while (<OLD>) {
    241 	    last if /\Q$end\E/;
    242 	}
    243 	print NEW;
    244     }
    245 
    246     close(OLD);
    247     close(NEW) || die("$file.new close: $!");
    248     &swapfile($file);
    249 }
    250 
    251 #-----------------------------------------------------------------------------
    252 
    253 sub swapfile {
    254     my ($f) = @_;
    255     if ( ! -f "$f.save") {
    256 	system "cp $f $f.save";
    257     }
    258     open(ORIG, $f);
    259     open(NEW, "$f.new");
    260     while (<ORIG>) {
    261 	$n = <NEW>;
    262 	if ($n ne $_) {
    263 	    close(ORIG);
    264 	    close(NEW);
    265 	    print "  Updating $f\n";
    266 	    rename "$f", "$f.old";
    267 	    rename "$f.new", "$f";
    268 	    return;
    269 	}
    270     }
    271     close(ORIG);
    272     close(NEW);
    273     print "  No change to $f\n";
    274     unlink "$f.new";
    275 }
    276