| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523 |
- (*$I+,R+,S+,A-,V-,N+,O-*)
- MODULE m2locate;
- IMPORT Lib,Str,FIO,IO,Storage;
- (* This program is used to locate an MSDOS exe file.
- The output is in Absolute Binary format,
- suitable for blowing a stand-alone system into PROM.
- The memory layout of the target system is specified in the
- .mem file, together with the linker classes which are to be
- put in the memory, for example:
- rom F0000 FFFF0 CODE FCODE
- ram 80000 E0000 DATA Dummy BSS M_DATA HEAP STACK
- The second address is a 'stop' address, so that a warning can
- be produced if there is not enough memory.
- *)
- CONST
- cNamePos = 4; (* change to 3 if it is required to locate segments rather than classes *)
- CONST
- Delim = Str.CHARSET{' '};
- ImageBufMax=4000H;
- TYPE
- StringType = ARRAY [0..31] OF CHAR;
- LongStringType = ARRAY [0..511] OF CHAR;
- UnitType = RECORD
- Name:StringType;
- Start,Stop:LONGCARD;
- StartSeg:CARDINAL;
- Diff:CARDINAL;
- Located:BOOLEAN;
- Rom:BOOLEAN;
- MemStart:LONGCARD;
- END;
- ExeHeaderType = RECORD
- magic : CARDINAL;
- sizemod512 : CARDINAL;
- sizediv512 : CARDINAL;
- numrelocitem : CARDINAL;
- headerparas : CARDINAL;
- heapminparas : CARDINAL;
- heapmaxparas : CARDINAL;
- initialss : CARDINAL;
- initialsp : CARDINAL;
- checksum : CARDINAL;
- initialip : CARDINAL;
- initialcs : CARDINAL;
- relocations : CARDINAL;
- ovrlay : CARDINAL;
- undocumented : CARDINAL;
- (* relocation items follow *)
- END;
- ImageType = RECORD
- index:CARDINAL;
- pos,size:LONGCARD;
- buf:ARRAY [0..ImageBufMax] OF SHORTCARD; (* note extra byte at start *)
- (* this is required to deal with fixups to the last byte of the buffer *)
- (* which are deferred until the next buffer load is read *)
- END;
- VAR
- ExeFile,
- MapFile,
- MemFile,
- Mp2File : FIO.File;
- BinFile : ARRAY[1..4] OF FIO.File;
- MemWidth : CARDINAL;
- Image : ImageType;
- ExeHeader : ExeHeaderType;
- HeaderSize:LONGCARD; (* size of exeheader in bytes *)
- NosUnit:CARDINAL;
- Unit:ARRAY [1..300] OF UnitType;
- PROCEDURE ReadHex( s:ARRAY OF BYTE; i:CARDINAL ):LONGCARD;
- VAR
- res:LONGCARD;
- c:SHORTCARD;
- BEGIN
- res := 0;
- LOOP
- c := SHORTCARD(s[i]);
- INC(i);
- CASE CHAR(c) OF
- | 'A'..'F': c := c - ( SHORTCARD('A') - 10 ) ;
- | '0'..'9': c := c - SHORTCARD('0');
- ELSE EXIT;
- END;
- res := res * 16 + VAL(LONGCARD, c );
- END;
- RETURN res;
- END ReadHex;
- PROCEDURE ReadMapFile;
- VAR
- cname,token:StringType;
- line:LongStringType;
- BEGIN
- NosUnit := 0;
- REPEAT
- FIO.RdStr(MapFile,line) ;
- UNTIL (line[0]<>CHAR(0)) AND (line[1]>='0') AND (line[1]<='9') ;
- LOOP
- IF Str.Length(line) < 40 THEN EXIT END;
- Str.Item( cname, line, Delim, cNamePos );
- IF ( NosUnit = 0 )
- OR ( Str.Compare(cname,Unit[NosUnit].Name) <> 0 )
- THEN
- INC(NosUnit);
- WITH Unit[NosUnit] DO
- Name := cname;
- Str.Item( token, line, Delim, 0 );
- Start := ReadHex( token,0 );
- StartSeg := CARDINAL(Start DIV 16);
- Located := FALSE;
- Rom := FALSE;
- Diff := 0;
- END;
- END;
- IF ( NosUnit <> 0 ) THEN
- Str.Item( token, line, Delim, 1 );
- Unit[NosUnit].Stop := ReadHex( token, 0 );
- END;
- FIO.RdStr(MapFile,line);
- END;
- IF NosUnit = 0 THEN
- IO.WrStr('Bad .map file');
- HALT;
- END;
- Unit[NosUnit+1] := Unit[NosUnit]; (* sentinel *)
- END ReadMapFile;
- PROCEDURE ClassSearch( cname:ARRAY OF CHAR ):CARDINAL;
- VAR i:CARDINAL;
- BEGIN
- i := 1;
- WHILE ( i <= NosUnit ) AND ( Str.Compare( Unit[i].Name, cname ) <> 0 ) DO
- INC(i);
- END;
- RETURN i;
- END ClassSearch;
- PROCEDURE ReadMemFile;
- VAR
- cname,token:StringType;
- line:LongStringType;
- memstart,memstop:LONGCARD;
- rom:BOOLEAN;
- ram:BOOLEAN;
- i,item:CARDINAL;
- BEGIN
- MemWidth := 1; (* default width *)
- LOOP
- FIO.RdStr(MemFile,line);
- Str.Item( token, line, Delim, 0 );
- ram := FALSE;
- rom := FALSE;
- IF Str.Compare(token,'') = 0 THEN
- EXIT;
- ELSIF Str.Compare(token,'rom') = 0 THEN
- rom := TRUE;
- ELSIF Str.Compare(token,'ram') = 0 THEN
- ram := TRUE;
- ELSIF Str.Compare(token,'width') = 0 THEN
- Str.Item( token, line, Delim, 1 );
- MemWidth := CARDINAL( ReadHex( token,0 ) );
- ELSE
- IO.WrStr('Bad .mem file');
- HALT;
- END;
- IF rom OR ram THEN
- Str.Item( token, line, Delim, 1 );
- memstart := ReadHex( token,0 );
- Str.Item( token, line, Delim, 2 );
- memstop := ReadHex( token,0 );
- item := 3;
- LOOP
- Str.Item( cname, line, Delim, item );
- INC(item);
- IF cname[0]=CHAR(0) THEN
- EXIT;
- END;
- (* search table *)
- i := ClassSearch( cname );
- IF i > NosUnit THEN
- IO.WrStr('Warning: ');
- IO.WrStr(cname);
- IO.WrStr(' not found in .map file');
- IO.WrLn;
- ELSE
- INC( memstart, LONGCARD( CARDINAL(Unit[i].Start-memstart) MOD 16 ));
- Unit[i].MemStart := memstart;
- IF Unit[i].Located THEN
- IO.WrStr('Warning : ');
- IO.WrStr(cname);
- IO.WrStr(' specified more than once in .mem file');
- IO.WrLn;
- END;
- Unit[i].Located := TRUE;
- Unit[i].Rom := rom;
- Unit[i].Diff := CARDINAL( (Unit[i].Start-memstart) DIV 16 );
- INC( memstart, Unit[i].Stop - Unit[i].Start );
- IF memstart > memstop THEN
- IO.WrStr('Warning: not enough memory for ');
- IO.WrStr(cname);
- IO.WrLn;
- END;
- END;
- END;
- END;
- END;
- END ReadMemFile;
- PROCEDURE NewSeg( seg,off:CARDINAL ):CARDINAL;
- VAR loc:LONGCARD;
- k:CARDINAL;
- BEGIN
- loc := 16*VAL(LONGCARD,seg) + VAL(LONGCARD,off);
- k := 1;
- (* search for location segment = k *)
- WHILE ( k <= NosUnit ) AND ( loc >= Unit[k].Start ) DO INC(k) END;
- DEC(k);
- RETURN seg - Unit[k].Diff;
- END NewSeg;
- PROCEDURE ChkRead( VAR buf:ARRAY OF BYTE; count:CARDINAL );
- BEGIN
- IF FIO.RdBin( ExeFile, buf, count ) <> count THEN
- IO.WrStr('?? on read');
- HALT;
- END;
- END ChkRead;
- PROCEDURE GetByte():SHORTCARD;
- VAR
- pindex:CARDINAL;
- fixlocabs:LONGCARD;
- target:CARDINAL;
- wp:POINTER TO CARDINAL;
- exefix:RECORD off,seg:CARDINAL END;
- dummy:CARDINAL;
- i,j:CARDINAL;
- BEGIN
- IF Image.pos >= Image.size THEN
- INC(Image.pos);
- RETURN 99H;
- END;
- IF Image.index >= ImageBufMax THEN
- IF Image.pos = 0 THEN
- Image.index := 1;
- ELSE
- Image.buf[0] := Image.buf[ImageBufMax];
- Image.index := 0;
- END;
- FIO.Seek( ExeFile, HeaderSize+Image.pos+LONGCARD(1-Image.index) );
- dummy := FIO.RdBin( ExeFile, Image.buf[1], SIZE(Image.buf)-1 );
- (* now apply segment fixups for this buffer *)
- FIO.Seek( ExeFile, LONGCARD(ExeHeader.relocations) );
- FOR i := 1 TO ExeHeader.numrelocitem DO
- ChkRead( exefix, SIZE(exefix) );
- fixlocabs := VAL(LONGCARD,exefix.off)+16*VAL(LONGCARD,exefix.seg);
- IF fixlocabs - Image.pos <= ImageBufMax THEN
- pindex := CARDINAL(fixlocabs-Image.pos) + Image.index;
- IF pindex < ImageBufMax THEN
- wp := ADR(Image.buf[pindex]);
- target := wp^;
- j := 0;
- LOOP (* search for target segment = j *)
- INC(j);
- IF ( j > NosUnit ) OR ( target < Unit[j].StartSeg ) THEN
- EXIT;
- END;
- END;
- DEC(j);
- wp^ := target - Unit[j].Diff;
- END;
- END;
- END;
- END;
- INC(Image.pos);
- INC(Image.index);
- RETURN Image.buf[Image.index-1];
- END GetByte;
- VAR OutPos : LONGCARD;
- PROCEDURE PutByte( b:SHORTCARD );
- BEGIN
- FIO.WrBin( BinFile[1+(CARDINAL(OutPos) MOD MemWidth)], b, 1 );
- INC( OutPos );
- END PutByte;
- PROCEDURE PutUnit( unit:UnitType );
- VAR
- total:LONGCARD;
- dummy:SHORTCARD;
- buf:ARRAY [0..15] OF SHORTCARD;
- i,count,seg,off:CARDINAL;
- BEGIN
- IF NOT unit.Located THEN
- IO.WrStr('Warning: ');
- IO.WrStr(unit.Name);
- IO.WrStr(' not located ');
- IO.WrLn;
- END;
- total := unit.Stop-unit.Start;
- IF total > 0 THEN
- IF unit.Rom THEN
- WHILE Image.pos < unit.Start DO
- dummy := GetByte();
- END;
- IF unit.Start <> Image.pos THEN
- IO.WrStr('Overshoot error??');
- IO.WrLngHex(unit.Start,6);
- IO.WrLngHex(Image.pos,6);
- HALT;
- END;
- IF OutPos = 0 THEN
- OutPos := unit.MemStart;
- ELSE
- WHILE OutPos < unit.MemStart DO
- PutByte(0FFH);
- END;
- END;
- WHILE total > 0 DO
- PutByte( GetByte() );
- DEC(total);
- END;
- END;
- END;
- END PutUnit;
- PROCEDURE WriteBinFile;
- VAR
- i:CARDINAL;
- BEGIN
- ChkRead( ExeHeader, SIZE(ExeHeader) );
- HeaderSize := VAL(LONGCARD,ExeHeader.headerparas)*16;
- Image.size := FIO.Size(ExeFile)-HeaderSize;
- Image.pos := 0;
- Image.index := ImageBufMax;
- OutPos := 0;
- FOR i := 1 TO NosUnit DO
- PutUnit( Unit[i] );
- END;
- END WriteBinFile;
- PROCEDURE Hex(n:CARDINAL):CHAR;
- BEGIN
- n := n MOD 16;
- IF n > 9 THEN
- RETURN CHAR( n + ORD('A') - 10 )
- ELSE
- RETURN CHAR( n + ORD('0') );
- END;
- END Hex;
- PROCEDURE EditMap;
- VAR
- line:LongStringType;
- i:CARDINAL;
- seg,off:CARDINAL;
- addr:LONGCARD;
- k:CARDINAL;
- cname:StringType;
- start:RECORD
- off,seg:CARDINAL;
- END;
- BEGIN
- k := 0;
- FIO.Seek(MapFile,0);
- LOOP
- FIO.RdStr(MapFile,line);
- IF FIO.EOF THEN EXIT END;
- IF ( line[0] = ' ' ) AND ( line[6] = 'H' ) THEN
- Str.Item( cname, line, Delim, cNamePos );
- k := ClassSearch(cname);
- IF k <= NosUnit THEN
- FOR i := 0 TO 7 BY 7 DO
- addr := ReadHex(line,i+1);
- seg := CARDINAL(addr DIV 16);
- off := CARDINAL(addr) MOD 16;
- seg := seg - Unit[k].Diff;
- line[i+4] := Hex(seg); seg := seg DIV 16;
- line[i+3] := Hex(seg); seg := seg DIV 16;
- line[i+2] := Hex(seg); seg := seg DIV 16;
- line[i+1] := Hex(seg); seg := seg DIV 16;
- END;
- END;
- ELSIF ( line[0] = 'P' ) THEN
- seg := CARDINAL(ReadHex(line,23));
- off := CARDINAL(ReadHex(line,28));
- seg := NewSeg(seg,off);
- start.seg := seg;
- start.off := off;
- line[26] := Hex(seg); seg := seg DIV 16;
- line[25] := Hex(seg); seg := seg DIV 16;
- line[24] := Hex(seg); seg := seg DIV 16;
- line[23] := Hex(seg); seg := seg DIV 16;
- ELSE
- FOR i := 5 TO Str.Length(line) DO
- IF ( line[i] = ':' ) THEN
- seg := CARDINAL(ReadHex(line,i-4));
- off := CARDINAL(ReadHex(line,i+1));
- seg := NewSeg( seg, off );
- line[i-1] := Hex(seg); seg := seg DIV 16;
- line[i-2] := Hex(seg); seg := seg DIV 16;
- line[i-3] := Hex(seg); seg := seg DIV 16;
- line[i-4] := Hex(seg); seg := seg DIV 16;
- END;
- END;
- END;
- IF line[0] <> CHAR(0) THEN
- FIO.WrStr(Mp2File,line);
- END;
- FIO.WrLn(Mp2File);
- END;
- END EditMap;
- PROCEDURE PrintSummary;
- VAR i:CARDINAL;
- BEGIN
- FOR i := 1 TO NosUnit DO
- WITH Unit[i] DO
- IO.WrStr(' Start='); IO.WrLngHex(Start,6);
- IO.WrStr(' ');
- IO.WrStr(' Stop='); IO.WrLngHex(Stop,6);
- IO.WrStr(' ');
- IF Located THEN
- IO.WrStr('MemStart=');
- IO.WrLngHex(MemStart,6);
- IO.WrStr(' ');
- ELSE
- IO.WrStr('Not located ');
- END;
- IO.WrStr(Name);
- IO.WrLn;
- END;
- END;
- END PrintSummary;
- PROCEDURE GiveBuf( f:FIO.File );
- TYPE buf = ARRAY [1..800H+FIO.BufferOverhead] OF SHORTCARD;
- VAR bufp :POINTER TO buf;
- BEGIN
- Storage.ALLOCATE(bufp,SIZE(buf));
- FIO.AssignBuffer(f,bufp^);
- END GiveBuf;
- PROCEDURE Create(ext:ARRAY OF CHAR):FIO.File;
- VAR
- filename:FIO.PathStr;
- res:FIO.File;
- BEGIN
- Str.Concat( filename, Lib.CommandLine^, ext );
- res := FIO.Create(filename);
- GiveBuf(res);
- RETURN res;
- END Create;
- PROCEDURE Open(ext:ARRAY OF CHAR):FIO.File;
- VAR
- filename:FIO.PathStr;
- res:FIO.File;
- BEGIN
- Str.Concat( filename, Lib.CommandLine^, ext );
- res := FIO.Open(filename);
- GiveBuf(res);
- RETURN res;
- END Open;
- BEGIN
- IO.WrStr('TopSpeed Locator Version 1.10');
- IO.WrLn;
- IO.WrStr('Copyright (C) 1987,1988 Jensen & Partners International');
- IO.WrLn;
- ExeFile := Open('.exe'); (* no buffering because random access *)
- MemFile := Open('.mem');
- MapFile := Open('.map');
- Mp2File := Create('.mp2');
- ReadMapFile;
- ReadMemFile;
- BinFile[1] := Create('.bn1');
- IF MemWidth > 1 THEN
- BinFile[2] := Create('.bn2');
- END;
- IF MemWidth > 2 THEN
- BinFile[3] := Create('.bn3');
- BinFile[4] := Create('.bn4');
- END;
- (*PrintSummary;*)
- WriteBinFile;
- EditMap;
- FIO.Close(ExeFile);
- FIO.Close(MemFile);
- FIO.Close(MapFile);
- FIO.Close(Mp2File);
- FIO.Close(BinFile[1]);
- IF MemWidth > 1 THEN
- FIO.Close(BinFile[2]);
- END;
- IF MemWidth > 2 THEN
- FIO.Close(BinFile[3]);
- FIO.Close(BinFile[4]);
- END;
- END m2locate.
|