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