m2locate.mod 13 KB

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