#!/usr/bin/perl -w # mkrelocxex prototype in perl (will rewrite in C). # this version only supports init addresses, not run addresses. use bytes; die "usage: $0 \n" unless @ARGV == 3; open $lo, "<", $ARGV[0] or die "$ARGV[0]: $!\n"; open $hi, "<", $ARGV[1] or die "$ARGV[1]: $!\n"; open $out, ">", $ARGV[2] or die "$ARGV[2]: $!\n"; sub read_word { my $fh = shift; my ($a, $b); read($fh, $a, 1) || return undef; read($fh, $b, 1) || return undef; return ord($a) | (ord($b) << 8); } sub read_header { my ($start, $end); my ($a, $b); my $fh = shift; $start = read_word($fh) || return undef; if($start == 0xffff) { $start = read_word($fh) || return undef; } $end = read_word($fh) || return undef; return ($start, $end); } sub read_seg { my $fh = shift; my ($start, $end) = @_; my @bytes; for($start..($end)) { my $b; read($fh, $b, 1) || die "early EOF, WTF?\n"; push @bytes, ord($b); } return @bytes; } sub print_table { my ($name, $t) = @_; print "\n$name byte table:\n"; my $i = 0; for(@$t) { printf "\$%04x ", $_; print "\n" if $i && ($i & 10 == 0); } print "\n"; } ($start, $end) = read_header($lo); ($hi_start, $hi_end) = read_header($hi); printf("lo start/end: \$%04x/\$%04x\n", $start, $end); printf("hi start/end: \$%04x/\$%04x\n", $hi_start, $hi_end); if(($start % 0x100) || ($hi_start % 0x100)) { die "starting address not on a page boundary\n"; } if($start != ($hi_start - 0x100)) { die "starting addresses not one page apart\n"; } if(($hi_start != ($start + 0x0100)) || ($hi_end != ($end + 0x0100))) { die "mismatched segment lengths\n"; } @bytes = read_seg($lo, $start, $end); @hi_bytes = read_seg($hi, $hi_start, $hi_end); for($i = 0; $i < @bytes; $i++) { my ($a, $b) = ($bytes[$i], $hi_bytes[$i]); next if $a == $b; if($b == ($a + 1)) { push @hi_table, ($i + $start); } else { die "invalid difference (not 0 or 1)\n"; } } push(@hi_table, 0); print_table("hi", \@hi_table); print "table size: " . @hi_table . " bytes\n\n"; ($istart, $iend) = read_header($lo); #warn "istart $istart iend $iend\n"; if($istart == 0x2e2 && $iend == 0x2e3) { $init = read_word($lo); } # OK, make the output file now... print $out chr(0xff); print $out chr(0xff); #warn $start; print $out chr($start & 0xff); print $out chr($start >> 8); print $out chr($end & 0xff); print $out chr($end >> 8); print $out chr($_) for @bytes; open $r, "<", "reloc.xex" || die $!; (undef) = read_word($r); $rstart = read_word($r); $rend = read_word($r); $rlen = $rend - $rstart + 1; read $r, $rcode, $rlen; close $r; # 8-byte address table $rcode .= chr($start & 0xff); $rcode .= chr($start >> 8); $rcode .= chr($end & 0xff); $rcode .= chr($end >> 8); $rcode .= chr(0); $rcode .= chr(0); $rcode .= chr($init & 0xff); $rcode .= chr($init >> 8); for(@hi_table) { $rcode .= chr($_ & 0xff); $rcode .= chr($_ >> 8); } $rend = $rstart + length($rcode) - 1; #warn "$rstart $rend " . length($rcode); # don't really need a ffff header, makes it easier to read hexdumps. print $out chr(0xff); print $out chr(0xff); # segment start/end print $out chr($rstart & 0xff); print $out chr($rstart >> 8); print $out chr($rend & 0xff); print $out chr($rend >> 8); # segment contents (code + tables) print $out $rcode; # init address print $out chr(0xe2); print $out chr(0x02); print $out chr(0xe3); print $out chr(0x02); print $out chr($rstart & 0xff); print $out chr($rstart >> 8); close $out;