MinosLinker.Mod 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. MODULE MinosLinker; (** AUTHOR "fof"; PURPOSE "Link Minos Image. Standalone Linker taken from OSACompiler from Niklaus Wirth"; **)
  2. IMPORT Streams, Commands, Files, KernelLog;
  3. TYPE
  4. Name = ARRAY 32 OF CHAR;
  5. Command = RECORD name: Name; offset: LONGINT END;
  6. Module = POINTER TO RECORD
  7. name: Name;
  8. key: LONGINT;
  9. dbase, pbase: LONGINT;
  10. size, refcnt: LONGINT;
  11. next: Module;
  12. entries: LONGINT;
  13. entry: ARRAY 256 OF LONGINT;
  14. command: ARRAY 64 OF Command;
  15. END ;
  16. Linker* = OBJECT
  17. VAR
  18. first, last: Module;
  19. base, heap, descriptorBase, bodyBase: LONGINT;
  20. W: Streams.Writer;
  21. Out: Files.File; Rout: Files.Writer;
  22. code: ARRAY 256*1024 OF LONGINT; (* tt: increased image size to one megabyte *)
  23. plain, descriptors: BOOLEAN;
  24. PROCEDURE &InitLinker* (w: Streams.Writer; plain, descriptors: BOOLEAN);
  25. BEGIN W := w;
  26. SELF.plain := plain; SELF.descriptors := descriptors;
  27. END InitLinker;
  28. PROCEDURE SetPos (pos: LONGINT);
  29. BEGIN
  30. Rout.Update;
  31. IF pos > Out.Length () THEN
  32. Files.OpenWriter(Rout, Out, Out.Length ());
  33. pos := pos - Out.Length (); REPEAT Rout.Char (0X); DEC (pos) UNTIL pos = 0
  34. ELSE Files.OpenWriter(Rout, Out, pos)
  35. END;
  36. END SetPos;
  37. PROCEDURE WriteCodeBlock(len, adr: LONGINT);
  38. VAR i: LONGINT;
  39. BEGIN
  40. IF plain THEN SetPos (adr - base) ELSE Rout.RawLInt (len); Rout.RawLInt (adr) END;
  41. WHILE i < len DO Rout.RawLInt( code[i]); INC(i) END;
  42. IF ~plain & (len # 0) THEN Rout.RawLInt( 0) END
  43. END WriteCodeBlock;
  44. PROCEDURE Fixup(fixloc, offset, base: LONGINT; VAR entry: ARRAY OF LONGINT);
  45. VAR instr, next, pno: LONGINT;
  46. BEGIN
  47. WHILE fixloc # 0 DO
  48. instr := code[fixloc]; next := instr MOD 10000H;
  49. pno := instr DIV 10000H MOD 100H;
  50. IF instr DIV 1000000H MOD 100H = 0EBH THEN (* case BL *)
  51. instr := instr DIV 1000000H * 1000000H + (entry[pno] + offset - fixloc - 2) MOD 1000000H
  52. ELSE (*indir. proc. address or indir. variable address *) instr := entry[pno]*4 + base
  53. END ;
  54. code[fixloc] := instr; fixloc := next
  55. END
  56. END Fixup;
  57. PROCEDURE FixSelf(fixloc, base: LONGINT);
  58. VAR instr, next: LONGINT;
  59. BEGIN
  60. WHILE fixloc # 0 DO
  61. instr := code[fixloc]; next := instr MOD 10000H;
  62. code[fixloc] := instr DIV 10000H * 4 + base; fixloc := next
  63. END
  64. END FixSelf;
  65. PROCEDURE ThisMod(VAR modname: ARRAY OF CHAR; VAR success: BOOLEAN): Module;
  66. VAR mod, imp: Module;
  67. nofimp, nofentries, codelen, fix, fixself, i: LONGINT;
  68. R: Files.Reader; F: Files.File;
  69. name: Name;
  70. key, datasize: LONGINT;
  71. import: ARRAY 256 OF Module; (* tt: Increased from 16 to 256 *)
  72. fixroot: ARRAY 256 OF LONGINT; (* tt: Increased from 16 to 256 *)
  73. BEGIN
  74. success := TRUE;
  75. mod := first;
  76. WHILE (mod # NIL) & (mod.name # modname) DO mod := mod.next END ;
  77. IF mod = NIL THEN (*load*)
  78. (* W.String(" trying to load module with name: "); W.String(modname); W.Ln; W.Update; *)
  79. F := ThisFile(modname);
  80. IF F # NIL THEN
  81. Files.OpenReader(R, F, 0);
  82. NEW(mod); mod.next := NIL; mod.refcnt := 0;
  83. R.RawString( mod.name); R.RawLInt( mod.key);
  84. R.RawLInt( fixself);
  85. R.RawString( name); success := TRUE; i := 0;
  86. W.String( "module "); W.String( mod.name); W.String(" key: "); W.Hex( mod.key, -9); W.Ln();
  87. WHILE (name[0] # 0X) & success DO
  88. R.RawLInt (key); R.RawLInt (fix);
  89. (* W.String (" importing "); W.String(name); W.String(" Key: " );
  90. W.Hex (key, 9); W.String(" fix: "); W.Int (fix, 6); W.Ln; W.Update;
  91. *) imp := ThisMod(name, success);
  92. IF imp # NIL THEN
  93. IF (key = imp.key) THEN
  94. import[i] := imp; INC (imp.refcnt); fixroot[i] := fix; INC(i)
  95. ELSE success := FALSE;
  96. W.String( name); W.String( " wrong version");
  97. W.Ln(); W.Update();
  98. END ;
  99. ELSE success := FALSE;
  100. W.String( name); W.String( " not found");
  101. W.Ln();
  102. END ;
  103. R.RawString( name); W.Update()
  104. END ;
  105. nofimp := i;
  106. IF success THEN
  107. IF first = NIL THEN first := mod ELSE last.next := mod END; last := mod;
  108. i := 0; R.RawString( mod.command[i].name);
  109. WHILE mod.command[i].name[0] # 0X DO (*skip commands*)
  110. R.RawLInt( mod.command[i].offset); INC (i);
  111. R.RawString( mod.command[i].name);
  112. END ;
  113. R.RawLInt( nofentries); R.RawLInt( mod.entry[0]); i := 0;
  114. W.String("modEntry ="); W.Int(mod.entry[0],1); W.Ln;
  115. WHILE i < nofentries DO INC(i); R.RawLInt( mod.entry[i]) END ; INC (i); mod.entry[i] := 0; mod.entries := i;
  116. mod.dbase := heap; R.RawLInt( datasize); INC (heap, datasize); mod.pbase := heap;
  117. R.RawLInt( codelen); mod.size := codelen*4; INC (heap, mod.size); i := 0;
  118. WHILE i < codelen DO R.RawLInt( code[i]); INC(i) END ;
  119. FixSelf(fixself, mod.pbase); i := 0;
  120. WHILE i < nofimp DO
  121. Fixup(fixroot[i], (import[i].pbase - mod.pbase) DIV 4, import[i].pbase, import[i].entry); INC(i)
  122. END ;
  123. W.String( " loading "); W.String( mod.name);
  124. W.Int( codelen*4, 6);
  125. W.String(" ");
  126. W.Hex( mod.dbase,-8);
  127. W.String(" ");
  128. W.Hex( mod.pbase,-8);
  129. W.String(" ");
  130. W.Hex( mod.entry[0]*4 + mod.pbase,-8);
  131. WriteCodeBlock(codelen, mod.pbase)
  132. END
  133. ELSE
  134. W.String( modname); W.String( " not found");
  135. success := FALSE;
  136. END;
  137. W.Ln(); W.Update();
  138. END ;
  139. RETURN mod
  140. END ThisMod;
  141. PROCEDURE Bodies;
  142. VAR len, base: LONGINT; mod: Module;
  143. BEGIN
  144. len := 0; base := heap; mod := first;
  145. WHILE mod # NIL DO
  146. code[len] := BodyBranch (mod, heap); INC (len); INC (heap, 4);
  147. mod := mod.next;
  148. END;
  149. code[len] := Branch (heap, heap); INC (len); INC (heap, 4);
  150. WriteCodeBlock (len, base);
  151. END Bodies;
  152. PROCEDURE String (VAR str: ARRAY OF CHAR; VAR index: LONGINT);
  153. VAR i, len: LONGINT;
  154. BEGIN
  155. len := 0; WHILE str[len] # 0X DO INC (len) END; i := 0;
  156. WHILE i <= len DO
  157. code[index] := ORD (str[i]) + ORD (str[i+1]) * 100H + ORD (str[i+2]) * 10000H + ORD (str[i+3]) * 1000000H;
  158. INC (index); INC (i, 4)
  159. END;
  160. END String;
  161. PROCEDURE ModuleDescriptors;
  162. VAR mod: Module; len, prevmod, prevcmd, i, cfix, efix: LONGINT;
  163. BEGIN
  164. mod := first; len := 0; prevmod := 0;
  165. WHILE mod # NIL DO
  166. (* Module *)
  167. (* W.String (mod.name); W.String (": "); W.Hex (heap + len * 4,9); W.Ln; W.Update; *)
  168. code[len] := prevmod; prevmod := heap + len * 4; INC (len);
  169. code[len] := mod.key; INC (len);
  170. code[len] := mod.dbase; INC (len);
  171. code[len] := mod.pbase; INC (len);
  172. code[len] := mod.size; INC (len);
  173. code[len] := mod.refcnt; INC (len);
  174. cfix := len; INC (len);
  175. efix := len; INC (len);
  176. String (mod.name, len);
  177. (* Commands *)
  178. i := 0; prevcmd := 0;
  179. WHILE mod.command[i].name[0] # 0X DO
  180. (* W.String (" "); W.String (mod.command[i].name); W.String (":"); W.Hex (heap + len * 4,10); W.Hex (mod.command[i].offset,10); W.Ln; W.Update; *)
  181. code[len] := prevcmd; prevcmd := heap + len * 4; INC (len);
  182. code[len] := mod.command[i].offset; INC (len);
  183. String (mod.command[i].name, len); INC (i)
  184. END;
  185. IF i # 0 THEN code[len] := 0; INC (len) END; (* sentinel *)
  186. code[cfix] := prevcmd;
  187. code[efix] := heap + len * 4; i := 0;
  188. (* W.String (" Entries:"); W.Ln; *)
  189. WHILE i # mod.entries DO
  190. (* W.String (" "); W.Int (i,0); W.String (": "); W.Hex (mod.entry[i], 0); W.Ln; *)
  191. code[len] := mod.entry[i]; INC (len); INC (i);
  192. END;
  193. mod := mod.next;
  194. END;
  195. WriteCodeBlock (len, heap);
  196. INC (heap, len * 4);
  197. code[0] := prevmod;
  198. WriteCodeBlock (1, descriptorBase);
  199. END ModuleDescriptors;
  200. PROCEDURE AddHeader(fileHeader: ARRAY OF CHAR; VAR success: BOOLEAN);
  201. VAR
  202. header: Files.File;
  203. in: Files.Reader;
  204. data, i: LONGINT;
  205. BEGIN
  206. i := 0;
  207. IF fileHeader # "" THEN
  208. header := Files.Old(fileHeader);
  209. IF header = NIL THEN
  210. W.String("Could not open header file "); W.String(fileHeader); W.Ln; W.Update;
  211. success := FALSE;
  212. ELSE
  213. Files.OpenReader(in, header, 0);
  214. WHILE in.Available() >= 4 DO
  215. in.RawLInt(data); code[i] := data; INC(heap, 4); INC(i);
  216. END;
  217. WriteCodeBlock(i, base);
  218. END;
  219. END;
  220. END AddHeader;
  221. PROCEDURE Begin* (base: LONGINT; fileOut, fileHeader: ARRAY OF CHAR; VAR success: BOOLEAN);
  222. BEGIN SELF.base := base; heap := base;
  223. first := NIL; last := NIL;
  224. Out := Files.New(fileOut); Files.OpenWriter(Rout, Out, 0);
  225. AddHeader(fileHeader, success);
  226. bodyBase := heap;
  227. IF plain THEN INC (heap, 4) END; (* jump to entry point *)
  228. IF descriptors THEN descriptorBase := heap; INC (heap, 4) END; (* pointer to first module descriptor *)
  229. END Begin;
  230. PROCEDURE Link*(fileIn: ARRAY OF CHAR; VAR success: BOOLEAN);
  231. VAR mod: Module;
  232. BEGIN
  233. success := TRUE;
  234. mod := ThisMod(fileIn, success);
  235. END Link;
  236. PROCEDURE End*;
  237. VAR link: LONGINT;
  238. fileName: Files.FileName;
  239. BEGIN
  240. IF first = NIL THEN
  241. W.String ("No output");
  242. ELSE
  243. IF descriptors THEN ModuleDescriptors END;
  244. link := heap; Bodies;
  245. IF plain THEN code[0] := Branch (link, bodyBase); WriteCodeBlock (1, bodyBase)
  246. ELSE WriteCodeBlock (0, link) END;
  247. Out.GetName(fileName); Rout.Update(); Files.Register(Out);
  248. W.String("Wrote image file "); W.String(fileName); W.Ln;
  249. W.String( "Output file length ="); W.Int( Out.Length(), -8); W.Char(' ');
  250. W.String("First entry at "); W.Hex( first.entry[0]*4 + first.pbase, -9); W.Ln(); W.Update();
  251. SELF.first := NIL; SELF.last := NIL; Out := NIL;
  252. END;
  253. END End;
  254. END Linker;
  255. PROCEDURE Branch (dest, pc: LONGINT): LONGINT;
  256. BEGIN RETURN LONGINT(0EA000000H) + ((dest - pc) DIV 4 - 2) MOD 1000000H
  257. END Branch;
  258. PROCEDURE BranchLink (dest, pc: LONGINT): LONGINT;
  259. BEGIN RETURN LONGINT(0EB000000H) + ((dest - pc) DIV 4 - 2) MOD 1000000H
  260. END BranchLink;
  261. PROCEDURE BodyBranch (m: Module; pc: LONGINT): LONGINT;
  262. BEGIN RETURN BranchLink (m.pbase + m.entry[0] * 4, pc);
  263. END BodyBranch;
  264. PROCEDURE ThisFile(name: ARRAY OF CHAR): Files.File;
  265. VAR i: INTEGER;
  266. BEGIN i := 0;
  267. WHILE name[i] # 0X DO INC(i) END ;
  268. name[i] := "."; name[i+1] := "a"; name[i+2] := "r"; name[i+3] := "m"; name[i+4] := 0X;
  269. RETURN Files.Old(name)
  270. END ThisFile;
  271. VAR
  272. log: Streams.Writer; (* logger to KernelLog *)
  273. PROCEDURE DoLink( linker: Linker; addHeaderFile: BOOLEAN; context: Commands.Context );
  274. VAR S: Streams.Reader; fileOut,fileIn, fileHeader: ARRAY 256 OF CHAR; base: LONGINT;
  275. success: BOOLEAN; intRes: LONGINT;
  276. BEGIN
  277. success := TRUE;
  278. S := context.arg;
  279. IF addHeaderFile THEN
  280. S.SkipWhitespace; S.String( fileHeader );
  281. ELSE
  282. fileHeader := "";
  283. END;
  284. S.SkipWhitespace; S.Int( base, TRUE );
  285. S.SkipWhitespace; S.String( fileOut );
  286. Files.Delete(fileOut, intRes); (* Try to delete an existing output file *)
  287. linker.Begin (base, fileOut, fileHeader, success);
  288. WHILE (S.res = Streams.Ok) & success DO
  289. S.SkipWhitespace; S.String( fileIn );
  290. IF fileIn[0] # 0X THEN linker.Link (fileIn, success) END;
  291. END;
  292. IF success THEN linker.End ELSE context.result := Commands.CommandError END;
  293. SetLog(NIL);
  294. END DoLink;
  295. PROCEDURE Link*( context: Commands.Context );
  296. VAR linker: Linker;
  297. BEGIN
  298. SetLog(context.out);
  299. NEW (linker, log, TRUE, TRUE);
  300. DoLink(linker, TRUE, context);
  301. SetLog(NIL);
  302. END Link;
  303. PROCEDURE SetLog*( Log: Streams.Writer );
  304. BEGIN
  305. IF Log = NIL THEN NEW( log, KernelLog.Send, 512 ) ELSE log := Log END;
  306. END SetLog;
  307. BEGIN
  308. SetLog( NIL );
  309. END MinosLinker.
  310. System.Free MinosLinker ~