TSLOCATE.MOD 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542
  1. (* Release 3.10 *)
  2. (*-------------------------------------------------------------------------*
  3. * *
  4. * TSLOCATE.MOD - Embedded code locator *
  5. * *
  6. * COPYRIGHT (C) 1989..1992 Clarion Software Corporation. *
  7. * All Rights Reserved *
  8. * *
  9. *--------------------------------------------------------------------------*)
  10. (*# call(near_call=>on,
  11. o_a_copy=>off) *)
  12. (*# check(index=>on,
  13. range=>off,
  14. stack=>on,
  15. overflow=>off) *)
  16. (*# optimize(alias=>on) *)
  17. MODULE tslocate;
  18. IMPORT Lib,Str,FIO,IO,Storage;
  19. (* This program is used to locate an MSDOS exe file.
  20. The output is in Absolute Binary format,
  21. suitable for blowing a stand-alone system into PROM.
  22. The memory layout of the target system is specified in the
  23. .mem file, together with the linker classes which are to be
  24. put in the memory, for example:
  25. rom F0000 FFFF0 CODE FCODE
  26. ram 80000 E0000 DATA Dummy BSS M_DATA HEAP STACK
  27. The second address is a 'stop' address, so that a warning can
  28. be produced if there is not enough memory.
  29. *)
  30. CONST
  31. cNamePos = 4; (* change to 3 if it is required to locate segments rather than classes *)
  32. CONST
  33. Delim = Str.CHARSET{' '};
  34. ImageBufMax=4000H;
  35. TYPE
  36. StringType = ARRAY [0..31] OF CHAR;
  37. LongStringType = ARRAY [0..511] OF CHAR;
  38. UnitType = RECORD
  39. Name:StringType;
  40. Start,Stop:LONGCARD;
  41. StartSeg:CARDINAL;
  42. Diff:CARDINAL;
  43. Located:BOOLEAN;
  44. Rom:BOOLEAN;
  45. MemStart:LONGCARD;
  46. END;
  47. ExeHeaderType = RECORD
  48. magic : CARDINAL;
  49. sizemod512 : CARDINAL;
  50. sizediv512 : CARDINAL;
  51. numrelocitem : CARDINAL;
  52. headerparas : CARDINAL;
  53. heapminparas : CARDINAL;
  54. heapmaxparas : CARDINAL;
  55. initialss : CARDINAL;
  56. initialsp : CARDINAL;
  57. checksum : CARDINAL;
  58. initialip : CARDINAL;
  59. initialcs : CARDINAL;
  60. relocations : CARDINAL;
  61. ovrlay : CARDINAL;
  62. undocumented : CARDINAL;
  63. (* relocation items follow *)
  64. END;
  65. ImageType = RECORD
  66. index:CARDINAL;
  67. pos,size:LONGCARD;
  68. buf:ARRAY [0..ImageBufMax] OF SHORTCARD; (* note extra byte at start *)
  69. (* this is required to deal with fixups to the last byte of the buffer *)
  70. (* which are deferred until the next buffer load is read *)
  71. END;
  72. VAR
  73. ExeFile,
  74. MapFile,
  75. MemFile,
  76. Mp2File : FIO.File;
  77. BinFile : ARRAY[1..4] OF FIO.File;
  78. MemWidth : CARDINAL;
  79. Image : ImageType;
  80. ExeHeader : ExeHeaderType;
  81. HeaderSize:LONGCARD; (* size of exeheader in bytes *)
  82. NosUnit:CARDINAL;
  83. Unit:ARRAY [1..300] OF UnitType;
  84. PROCEDURE ReadHex( s:ARRAY OF BYTE; i:CARDINAL ):LONGCARD;
  85. VAR
  86. res:LONGCARD;
  87. c:SHORTCARD;
  88. BEGIN
  89. res := 0;
  90. LOOP
  91. c := SHORTCARD(s[i]);
  92. INC(i);
  93. CASE CHAR(c) OF
  94. | 'A'..'F': c := c - ( SHORTCARD('A') - 10 ) ;
  95. | '0'..'9': c := c - SHORTCARD('0');
  96. ELSE EXIT;
  97. END;
  98. res := res * 16 + VAL(LONGCARD, c );
  99. END;
  100. RETURN res;
  101. END ReadHex;
  102. PROCEDURE ReadMapFile;
  103. VAR
  104. cname,token:StringType;
  105. line:LongStringType;
  106. BEGIN
  107. NosUnit := 0;
  108. REPEAT
  109. FIO.RdStr(MapFile,line) ;
  110. UNTIL (line[0]<>CHAR(0)) AND (line[1]>='0') AND (line[1]<='9') ;
  111. LOOP
  112. IF Str.Length(line) < 40 THEN EXIT END;
  113. Str.Item( cname, line, Delim, cNamePos );
  114. IF ( NosUnit = 0 )
  115. OR ( Str.Compare(cname,Unit[NosUnit].Name) <> 0 )
  116. THEN
  117. INC(NosUnit);
  118. WITH Unit[NosUnit] DO
  119. Name := cname;
  120. Str.Item( token, line, Delim, 0 );
  121. Start := ReadHex( token,0 );
  122. StartSeg := CARDINAL(Start DIV 16);
  123. Located := FALSE;
  124. Rom := FALSE;
  125. Diff := 0;
  126. END;
  127. END;
  128. IF ( NosUnit <> 0 ) THEN
  129. Str.Item( token, line, Delim, 1 );
  130. Unit[NosUnit].Stop := ReadHex( token, 0 );
  131. END;
  132. FIO.RdStr(MapFile,line);
  133. END;
  134. IF NosUnit = 0 THEN
  135. IO.WrStr('Bad .map file');
  136. HALT;
  137. END;
  138. Unit[NosUnit+1] := Unit[NosUnit]; (* sentinel *)
  139. END ReadMapFile;
  140. PROCEDURE ClassSearch( cname:ARRAY OF CHAR ):CARDINAL;
  141. VAR i:CARDINAL;
  142. BEGIN
  143. i := 1;
  144. WHILE ( i <= NosUnit ) AND ( Str.Compare( Unit[i].Name, cname ) <> 0 ) DO
  145. INC(i);
  146. END;
  147. RETURN i;
  148. END ClassSearch;
  149. PROCEDURE ReadMemFile;
  150. VAR
  151. cname,token:StringType;
  152. line:LongStringType;
  153. memstart,memstop:LONGCARD;
  154. rom:BOOLEAN;
  155. ram:BOOLEAN;
  156. i,item:CARDINAL;
  157. BEGIN
  158. MemWidth := 1; (* default width *)
  159. LOOP
  160. FIO.RdStr(MemFile,line);
  161. Str.Item( token, line, Delim, 0 );
  162. ram := FALSE;
  163. rom := FALSE;
  164. IF Str.Compare(token,'') = 0 THEN
  165. EXIT;
  166. ELSIF Str.Compare(token,'rom') = 0 THEN
  167. rom := TRUE;
  168. ELSIF Str.Compare(token,'ram') = 0 THEN
  169. ram := TRUE;
  170. ELSIF Str.Compare(token,'width') = 0 THEN
  171. Str.Item( token, line, Delim, 1 );
  172. MemWidth := CARDINAL( ReadHex( token,0 ) );
  173. ELSE
  174. IO.WrStr('Bad .mem file');
  175. HALT;
  176. END;
  177. IF rom OR ram THEN
  178. Str.Item( token, line, Delim, 1 );
  179. memstart := ReadHex( token,0 );
  180. Str.Item( token, line, Delim, 2 );
  181. memstop := ReadHex( token,0 );
  182. item := 3;
  183. LOOP
  184. Str.Item( cname, line, Delim, item );
  185. INC(item);
  186. IF cname[0]=CHAR(0) THEN
  187. EXIT;
  188. END;
  189. (* search table *)
  190. i := ClassSearch( cname );
  191. IF i > NosUnit THEN
  192. IO.WrStr('Warning: ');
  193. IO.WrStr(cname);
  194. IO.WrStr(' not found in .map file');
  195. IO.WrLn;
  196. ELSE
  197. INC( memstart, LONGCARD( CARDINAL(Unit[i].Start-memstart) MOD 16 ));
  198. Unit[i].MemStart := memstart;
  199. IF Unit[i].Located THEN
  200. IO.WrStr('Warning : ');
  201. IO.WrStr(cname);
  202. IO.WrStr(' specified more than once in .mem file');
  203. IO.WrLn;
  204. END;
  205. Unit[i].Located := TRUE;
  206. Unit[i].Rom := rom;
  207. Unit[i].Diff := CARDINAL( (Unit[i].Start-memstart) DIV 16 );
  208. INC( memstart, Unit[i].Stop - Unit[i].Start );
  209. IF memstart > memstop THEN
  210. IO.WrStr('Warning: not enough memory for ');
  211. IO.WrStr(cname);
  212. IO.WrLn;
  213. END;
  214. END;
  215. END;
  216. END;
  217. END;
  218. END ReadMemFile;
  219. PROCEDURE NewSeg( seg,off:CARDINAL ):CARDINAL;
  220. VAR loc:LONGCARD;
  221. k:CARDINAL;
  222. BEGIN
  223. loc := 16*VAL(LONGCARD,seg) + VAL(LONGCARD,off);
  224. k := 1;
  225. (* search for location segment = k *)
  226. WHILE ( k <= NosUnit ) AND ( loc >= Unit[k].Start ) DO INC(k) END;
  227. DEC(k);
  228. RETURN seg - Unit[k].Diff;
  229. END NewSeg;
  230. PROCEDURE ChkRead( VAR buf:ARRAY OF BYTE; count:CARDINAL );
  231. BEGIN
  232. IF FIO.RdBin( ExeFile, buf, count ) <> count THEN
  233. IO.WrStr('?? on read');
  234. HALT;
  235. END;
  236. END ChkRead;
  237. PROCEDURE GetByte():SHORTCARD;
  238. VAR
  239. pindex:CARDINAL;
  240. fixlocabs:LONGCARD;
  241. target:CARDINAL;
  242. wp:POINTER TO CARDINAL;
  243. exefix:RECORD off,seg:CARDINAL END;
  244. dummy:CARDINAL;
  245. i,j:CARDINAL;
  246. BEGIN
  247. IF Image.pos >= Image.size THEN
  248. INC(Image.pos);
  249. RETURN 99H;
  250. END;
  251. IF Image.index >= ImageBufMax THEN
  252. IF Image.pos = 0 THEN
  253. Image.index := 1;
  254. ELSE
  255. Image.buf[0] := Image.buf[ImageBufMax];
  256. Image.index := 0;
  257. END;
  258. FIO.Seek( ExeFile, HeaderSize+Image.pos+LONGCARD(1-Image.index) );
  259. dummy := FIO.RdBin( ExeFile, Image.buf[1], SIZE(Image.buf)-1 );
  260. (* now apply segment fixups for this buffer *)
  261. FIO.Seek( ExeFile, LONGCARD(ExeHeader.relocations) );
  262. FOR i := 1 TO ExeHeader.numrelocitem DO
  263. ChkRead( exefix, SIZE(exefix) );
  264. fixlocabs := VAL(LONGCARD,exefix.off)+16*VAL(LONGCARD,exefix.seg);
  265. IF fixlocabs - Image.pos <= ImageBufMax THEN
  266. pindex := CARDINAL(fixlocabs-Image.pos) + Image.index;
  267. IF pindex < ImageBufMax THEN
  268. wp := ADR(Image.buf[pindex]);
  269. target := wp^;
  270. j := 0;
  271. LOOP (* search for target segment = j *)
  272. INC(j);
  273. IF ( j > NosUnit ) OR ( target < Unit[j].StartSeg ) THEN
  274. EXIT;
  275. END;
  276. END;
  277. DEC(j);
  278. wp^ := target - Unit[j].Diff;
  279. END;
  280. END;
  281. END;
  282. END;
  283. INC(Image.pos);
  284. INC(Image.index);
  285. RETURN Image.buf[Image.index-1];
  286. END GetByte;
  287. VAR OutPos : LONGCARD;
  288. PROCEDURE PutByte( b:SHORTCARD );
  289. BEGIN
  290. FIO.WrBin( BinFile[1+(CARDINAL(OutPos) MOD MemWidth)], b, 1 );
  291. INC( OutPos );
  292. END PutByte;
  293. PROCEDURE PutUnit( unit:UnitType );
  294. VAR
  295. total:LONGCARD;
  296. dummy:SHORTCARD;
  297. buf:ARRAY [0..15] OF SHORTCARD;
  298. i,count,seg,off:CARDINAL;
  299. BEGIN
  300. IF NOT unit.Located THEN
  301. IO.WrStr('Warning: ');
  302. IO.WrStr(unit.Name);
  303. IO.WrStr(' not located ');
  304. IO.WrLn;
  305. END;
  306. total := unit.Stop-unit.Start;
  307. IF total > 0 THEN
  308. IF unit.Rom THEN
  309. WHILE Image.pos < unit.Start DO
  310. dummy := GetByte();
  311. END;
  312. IF unit.Start <> Image.pos THEN
  313. IO.WrStr('Overshoot error??');
  314. IO.WrLngHex(unit.Start,6);
  315. IO.WrLngHex(Image.pos,6);
  316. HALT;
  317. END;
  318. IF OutPos = 0 THEN
  319. OutPos := unit.MemStart;
  320. ELSE
  321. WHILE OutPos < unit.MemStart DO
  322. PutByte(0FFH);
  323. END;
  324. END;
  325. WHILE total > 0 DO
  326. PutByte( GetByte() );
  327. DEC(total);
  328. END;
  329. END;
  330. END;
  331. END PutUnit;
  332. PROCEDURE WriteBinFile;
  333. VAR
  334. i:CARDINAL;
  335. BEGIN
  336. ChkRead( ExeHeader, SIZE(ExeHeader) );
  337. HeaderSize := VAL(LONGCARD,ExeHeader.headerparas)*16;
  338. Image.size := FIO.Size(ExeFile)-HeaderSize;
  339. Image.pos := 0;
  340. Image.index := ImageBufMax;
  341. OutPos := 0;
  342. FOR i := 1 TO NosUnit DO
  343. PutUnit( Unit[i] );
  344. END;
  345. END WriteBinFile;
  346. PROCEDURE Hex(n:CARDINAL):CHAR;
  347. BEGIN
  348. n := n MOD 16;
  349. IF n > 9 THEN
  350. RETURN CHAR( n + ORD('A') - 10 )
  351. ELSE
  352. RETURN CHAR( n + ORD('0') );
  353. END;
  354. END Hex;
  355. PROCEDURE EditMap;
  356. VAR
  357. line:LongStringType;
  358. i:CARDINAL;
  359. seg,off:CARDINAL;
  360. addr:LONGCARD;
  361. k:CARDINAL;
  362. cname:StringType;
  363. start:RECORD
  364. off,seg:CARDINAL;
  365. END;
  366. BEGIN
  367. k := 0;
  368. FIO.Seek(MapFile,0);
  369. LOOP
  370. FIO.RdStr(MapFile,line);
  371. IF FIO.EOF THEN EXIT END;
  372. IF ( line[0] = ' ' ) AND ( line[6] = 'H' ) THEN
  373. Str.Item( cname, line, Delim, cNamePos );
  374. k := ClassSearch(cname);
  375. IF k <= NosUnit THEN
  376. FOR i := 0 TO 7 BY 7 DO
  377. addr := ReadHex(line,i+1);
  378. seg := CARDINAL(addr DIV 16);
  379. off := CARDINAL(addr) MOD 16;
  380. seg := seg - Unit[k].Diff;
  381. line[i+4] := Hex(seg); seg := seg DIV 16;
  382. line[i+3] := Hex(seg); seg := seg DIV 16;
  383. line[i+2] := Hex(seg); seg := seg DIV 16;
  384. line[i+1] := Hex(seg); seg := seg DIV 16;
  385. END;
  386. END;
  387. ELSIF ( line[0] = 'P' ) THEN
  388. seg := CARDINAL(ReadHex(line,23));
  389. off := CARDINAL(ReadHex(line,28));
  390. seg := NewSeg(seg,off);
  391. start.seg := seg;
  392. start.off := off;
  393. line[26] := Hex(seg); seg := seg DIV 16;
  394. line[25] := Hex(seg); seg := seg DIV 16;
  395. line[24] := Hex(seg); seg := seg DIV 16;
  396. line[23] := Hex(seg); seg := seg DIV 16;
  397. ELSE
  398. FOR i := 5 TO Str.Length(line) DO
  399. IF ( line[i] = ':' ) THEN
  400. seg := CARDINAL(ReadHex(line,i-4));
  401. off := CARDINAL(ReadHex(line,i+1));
  402. seg := NewSeg( seg, off );
  403. line[i-1] := Hex(seg); seg := seg DIV 16;
  404. line[i-2] := Hex(seg); seg := seg DIV 16;
  405. line[i-3] := Hex(seg); seg := seg DIV 16;
  406. line[i-4] := Hex(seg); seg := seg DIV 16;
  407. END;
  408. END;
  409. END;
  410. IF line[0] <> CHAR(0) THEN
  411. FIO.WrStr(Mp2File,line);
  412. END;
  413. FIO.WrLn(Mp2File);
  414. END;
  415. END EditMap;
  416. PROCEDURE PrintSummary;
  417. VAR i:CARDINAL;
  418. BEGIN
  419. FOR i := 1 TO NosUnit DO
  420. WITH Unit[i] DO
  421. IO.WrStr(' Start='); IO.WrLngHex(Start,6);
  422. IO.WrStr(' ');
  423. IO.WrStr(' Stop='); IO.WrLngHex(Stop,6);
  424. IO.WrStr(' ');
  425. IF Located THEN
  426. IO.WrStr('MemStart=');
  427. IO.WrLngHex(MemStart,6);
  428. IO.WrStr(' ');
  429. ELSE
  430. IO.WrStr('Not located ');
  431. END;
  432. IO.WrStr(Name);
  433. IO.WrLn;
  434. END;
  435. END;
  436. END PrintSummary;
  437. PROCEDURE GiveBuf( f:FIO.File );
  438. TYPE buf = ARRAY [1..800H+FIO.BufferOverhead] OF SHORTCARD;
  439. VAR bufp :POINTER TO buf;
  440. BEGIN
  441. Storage.ALLOCATE(bufp,SIZE(buf));
  442. FIO.AssignBuffer(f,bufp^);
  443. END GiveBuf;
  444. PROCEDURE Create(ext:ARRAY OF CHAR):FIO.File;
  445. VAR
  446. filename:FIO.PathStr;
  447. res:FIO.File;
  448. BEGIN
  449. Str.Concat( filename, Lib.CommandLine^, ext );
  450. res := FIO.Create(filename);
  451. GiveBuf(res);
  452. RETURN res;
  453. END Create;
  454. PROCEDURE Open(ext:ARRAY OF CHAR):FIO.File;
  455. VAR
  456. filename:FIO.PathStr;
  457. res:FIO.File;
  458. BEGIN
  459. Str.Concat( filename, Lib.CommandLine^, ext );
  460. res := FIO.Open(filename);
  461. IF Str.Compare(ext, '.exe') # 0 THEN
  462. GiveBuf(res);
  463. END;
  464. RETURN res;
  465. END Open;
  466. BEGIN
  467. IO.WrStr('TopSpeed Locator Version 1.10');
  468. IO.WrLn;
  469. IO.WrStr('Copyright (C) 1987-1992 Clarion Software Corporation');
  470. IO.WrLn;
  471. ExeFile := Open('.exe'); (* no buffering because random access *)
  472. MemFile := Open('.mem');
  473. MapFile := Open('.map');
  474. Mp2File := Create('.mp2');
  475. ReadMapFile;
  476. ReadMemFile;
  477. BinFile[1] := Create('.bn1');
  478. IF MemWidth > 1 THEN
  479. BinFile[2] := Create('.bn2');
  480. END;
  481. IF MemWidth > 2 THEN
  482. BinFile[3] := Create('.bn3');
  483. BinFile[4] := Create('.bn4');
  484. END;
  485. (*PrintSummary;*)
  486. WriteBinFile;
  487. EditMap;
  488. FIO.Close(ExeFile);
  489. FIO.Close(MemFile);
  490. FIO.Close(MapFile);
  491. FIO.Close(Mp2File);
  492. FIO.Close(BinFile[1]);
  493. IF MemWidth > 1 THEN
  494. FIO.Close(BinFile[2]);
  495. END;
  496. IF MemWidth > 2 THEN
  497. FIO.Close(BinFile[3]);
  498. FIO.Close(BinFile[4]);
  499. END;
  500. END tslocate.
  501.