Loader.Mod 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905
  1. (* Aos, Copyright 2001, Pieter Muller, ETH Zurich *)
  2. MODULE Loader; (** AUTHOR "pjm"; PURPOSE "Active Oberon module loader plugin"; *)
  3. (* cf. Linker *)
  4. IMPORT SYSTEM, KernelLog, Commands, Heaps, Modules, Machine, Streams, Files;
  5. CONST
  6. Ok = 0;
  7. FileNotFound = 3401;
  8. TagInvalid = 3402;
  9. FileCorrupt = 3403;
  10. (*FileTooShort = 3404;*)
  11. IncompatibleImport = 3405;
  12. IncompatibleModuleName = 3406;
  13. AddressSize = SIZEOF (ADDRESS);
  14. MaxStructs = 1024; (* maximum number of structures in export block *)
  15. FileTag = 0BBX; (* cf. PCM.Mod *)
  16. NoZeroCompress = 0ADX; (* cf. PCM.Mod *)
  17. FileVersion* = 0B1X; (* cf. PCM.Mod *)
  18. FileVersionOC=0B2X; (* preparation for object and symbol file for new Oberon Compiler *)
  19. CurrentFileVersion=0B4X;
  20. (* object model exports *)
  21. EUEnd = 0; EURecord = 1; EUobjScope = 0; EUrecScope = 1; EUerrScope = -1;
  22. EUProcFlagBit = 31;
  23. Sentinel = LONGINT(0FFFFFFFFH);
  24. (* compiler flags *)
  25. UsesDefinitions = 31;
  26. DefinitionModule = "Interfaces"; (* runtime module that supplies definition support *)
  27. TYPE
  28. ObjHeader = RECORD (* data from object file header *)
  29. entries, commands, pointers, types, modules, links, dataLinks: LONGINT;
  30. codeSize, dataSize, refSize, constSize, exTableLen, procs, maxPtrs, crc: LONGINT;
  31. staticTdSize: LONGINT; (* ug *)
  32. name: Modules.Name
  33. END;
  34. DataLinkRec = RECORD
  35. mod: LONGINT;
  36. entry: LONGINT;
  37. fixups: LONGINT;
  38. ofs: POINTER TO ARRAY OF SIZE
  39. END;
  40. LinkRec = RECORD
  41. mod: LONGINT;
  42. entry: LONGINT;
  43. link: SIZE
  44. END;
  45. TypeRec = RECORD
  46. init: BOOLEAN;
  47. entry, methods, inhMethods, baseMod: LONGINT;
  48. baseEntry: ADDRESS;
  49. END;
  50. VAR
  51. trace: BOOLEAN;
  52. (* ReadHeader - Read object file header. *)
  53. PROCEDURE ReadHeader(r: Streams.Reader; VAR h: ObjHeader; VAR res: LONGINT; VAR msg: ARRAY OF CHAR);
  54. VAR symSize: LONGINT; flags: SET; ignore: Modules.Module; tag: CHAR;
  55. BEGIN
  56. r.Char(tag);
  57. IF tag = FileTag THEN
  58. r.Char(tag);
  59. IF tag = NoZeroCompress THEN r.Char(tag) END; (* no zero compression in symbol file *)
  60. IF (tag = FileVersion) OR (tag >= FileVersionOC) & (tag <= CurrentFileVersion) THEN
  61. IF tag = FileVersion THEN
  62. r.RawNum(symSize);
  63. ELSIF tag >= FileVersionOC THEN
  64. r.RawLInt(symSize)
  65. END;
  66. flags := {};
  67. r.SkipBytes(symSize); (* skip symbols *)
  68. r.RawLInt(h.refSize);
  69. r.RawLInt(h.entries);
  70. r.RawLInt(h.commands);
  71. r.RawLInt(h.pointers);
  72. r.RawLInt(h.types);
  73. r.RawLInt(h.modules);
  74. r.RawLInt(h.dataLinks);
  75. r.RawLInt(h.links);
  76. r.RawLInt(h.dataSize);
  77. r.RawLInt(h.constSize);
  78. r.RawLInt(h.codeSize);
  79. r.RawLInt(h.exTableLen);
  80. r.RawLInt(h.procs);
  81. r.RawLInt(h.maxPtrs);
  82. r.RawLInt(h.staticTdSize); (* ug *)
  83. IF ORD(tag) >= 0B4H THEN r.RawLInt(h.crc) END;
  84. r.RawString(h.name);
  85. IF trace THEN
  86. KernelLog.String(" name: "); KernelLog.String(h.name);
  87. KernelLog.String(" symSize: "); KernelLog.Int(symSize, 1);
  88. KernelLog.String(" refSize: "); KernelLog.Int(h.refSize, 1); KernelLog.Ln;
  89. KernelLog.String(" entries: "); KernelLog.Int(h.entries, 1);
  90. KernelLog.String(" commands: "); KernelLog.Int(h.commands, 1);
  91. KernelLog.String(" pointers: "); KernelLog.Int(h.pointers, 1);
  92. KernelLog.String(" types: "); KernelLog.Int(h.types, 1);
  93. KernelLog.String(" modules: "); KernelLog.Int(h.modules, 1); KernelLog.Ln;
  94. KernelLog.String(" dataLinks: "); KernelLog.Int(h.dataLinks, 1);
  95. KernelLog.String(" links: "); KernelLog.Int(h.links, 1);
  96. KernelLog.String(" dataSize: "); KernelLog.Int(h.dataSize, 1);
  97. KernelLog.String(" constSize: "); KernelLog.Int(h.constSize, 1);
  98. KernelLog.String(" codeSize: "); KernelLog.Int(h.codeSize, 1); KernelLog.Ln;
  99. KernelLog.String(" exTableLen: "); KernelLog.Int(h.exTableLen, 1);
  100. KernelLog.String(" procs: "); KernelLog.Int(h.procs, 1);
  101. KernelLog.String(" maxPtrs: "); KernelLog.Int(h.maxPtrs, 1);
  102. KernelLog.String(" staticTdSize: "); KernelLog.Int(h.staticTdSize, 1); KernelLog.Ln
  103. END;
  104. IF r.res # Streams.Ok THEN res := r.res END
  105. ELSE
  106. res := TagInvalid
  107. END
  108. ELSE
  109. res := TagInvalid
  110. END
  111. END ReadHeader;
  112. (* zero compressed strings don't like UTF-8 encoding *)
  113. PROCEDURE ReadString8(r: Streams.Reader; VAR str: ARRAY OF CHAR);
  114. VAR i: LONGINT; ch: CHAR;
  115. BEGIN
  116. i := 0;
  117. r.Char(ch);
  118. WHILE ch # 0X DO
  119. str[i] := ch; INC(i);
  120. r.Char(ch);
  121. END;
  122. str[i] := 0X;
  123. END ReadString8;
  124. PROCEDURE AllocateModule(m: Modules.Module; h: ObjHeader);
  125. VAR dataSize: SIZE;
  126. BEGIN
  127. dataSize := SYSTEM.VAL(SIZE, h.dataSize) + (-h.dataSize) MOD 8; (* round up to 8 to align constant block *)
  128. NEW(m.entry, h.entries);
  129. NEW(m.command, h.commands);
  130. NEW(m.ptrAdr, h.pointers);
  131. NEW(m.typeInfo, h.types);
  132. NEW(m.module, h.modules);
  133. NEW(m.data, dataSize + h.constSize);
  134. NEW(m.code, h.codeSize);
  135. NEW(m.staticTypeDescs, h.staticTdSize);
  136. NEW(m.refs, h.refSize);
  137. NEW(m.exTable, h.exTableLen);
  138. m.sb := ADDRESSOF(m.data[0]) + dataSize; (* constants positive, data negative *)
  139. END AllocateModule;
  140. (* ReadEntryBlock - Read the entry block. *)
  141. PROCEDURE ReadEntryBlock(r: Streams.Reader; m: Modules.Module): BOOLEAN;
  142. VAR tag: CHAR; i, num: LONGINT;
  143. BEGIN
  144. r.Char(tag);
  145. IF tag = 82X THEN (* entry tag *)
  146. FOR i := 0 TO LEN(m.entry)-1 DO
  147. r.RawNum(num);
  148. m.entry[i] := num + ADDRESSOF(m.code[0])
  149. END;
  150. (*ASSERT((m.entries > 0) & (m.entry[0] = ADDRESSOF(m.code[0])));*) (* entry[0] is beginning of code (cf. OPL.Init) *)
  151. RETURN TRUE
  152. ELSE
  153. RETURN FALSE
  154. END
  155. END ReadEntryBlock;
  156. (* ReadCommandBlock - Read the command block. *)
  157. PROCEDURE ReadCommandBlock(r: Streams.Reader; m: Modules.Module): BOOLEAN;
  158. VAR tag : CHAR; i, adr : LONGINT;
  159. BEGIN
  160. r.Char(tag);
  161. IF tag = 83X THEN (* command tag *)
  162. FOR i := 0 TO LEN(m.command)-1 DO
  163. r.RawNum(adr); m.command[i].argTdAdr := adr;
  164. r.RawNum(adr); m.command[i].retTdAdr := adr;
  165. r.RawString(m.command[i].name);
  166. r.RawNum(adr); m.command[i].entryAdr := adr;
  167. (* addresses will be fixed up later in FixupCommands *)
  168. END;
  169. RETURN TRUE
  170. ELSE
  171. RETURN FALSE
  172. END;
  173. END ReadCommandBlock;
  174. (* ReadPointerBlock - Read the pointer block. *)
  175. PROCEDURE ReadPointerBlock(r: Streams.Reader; m: Modules.Module): BOOLEAN;
  176. VAR tag: CHAR; i, num: LONGINT;
  177. BEGIN
  178. r.Char(tag);
  179. IF tag = 84X THEN (* pointer tag *)
  180. FOR i := 0 TO LEN(m.ptrAdr)-1 DO
  181. r.RawNum(num);
  182. ASSERT(num MOD AddressSize = 0); (* no deep copy flag *)
  183. m.ptrAdr[i] := m.sb + num
  184. END;
  185. RETURN TRUE
  186. ELSE
  187. RETURN FALSE
  188. END
  189. END ReadPointerBlock;
  190. (* ReadImportBlock - Read the import block. *)
  191. PROCEDURE ReadImportBlock(r: Streams.Reader; m: Modules.Module; VAR res: LONGINT;
  192. VAR msg: ARRAY OF CHAR): BOOLEAN;
  193. VAR tag: CHAR; i: LONGINT; name: Modules.Name;
  194. BEGIN
  195. r.Char(tag);
  196. IF tag = 85X THEN (* import tag *)
  197. i := 0;
  198. WHILE (i # LEN(m.module)) & (res = Ok) DO
  199. ReadString8(r, name);
  200. m.module[i] := Modules.ThisModule(name, res, msg); (* recursively load the imported module *)
  201. INC(i)
  202. END
  203. ELSE
  204. res := FileCorrupt
  205. END;
  206. RETURN res = Ok
  207. END ReadImportBlock;
  208. (* ReadDataLinkBlock - Read the data links block. *)
  209. PROCEDURE ReadDataLinkBlock(r: Streams.Reader; dataLinks: LONGINT; VAR d: ARRAY OF DataLinkRec): BOOLEAN;
  210. VAR tag: CHAR; i, j, num: LONGINT;
  211. BEGIN
  212. r.Char(tag);
  213. IF tag = 8DX THEN (* data links tag *)
  214. FOR i := 0 TO dataLinks-1 DO
  215. r.Char(tag); d[i].mod := ORD(tag);
  216. r.RawNum(num); d[i].entry := num;
  217. r.RawLInt(num); d[i].fixups := num; (* fixed size *)
  218. IF d[i].fixups > 0 THEN
  219. NEW(d[i].ofs, d[i].fixups);
  220. FOR j := 0 TO d[i].fixups-1 DO
  221. r.RawNum(num); d[i].ofs[j] := num
  222. END
  223. ELSE
  224. d[i].ofs := NIL
  225. END
  226. END;
  227. RETURN TRUE
  228. ELSE
  229. RETURN FALSE
  230. END
  231. END ReadDataLinkBlock;
  232. (* ReadLinkBlock - Read the link block. *)
  233. PROCEDURE ReadLinkBlock(r: Streams.Reader; links, entries: LONGINT; VAR l: ARRAY OF LinkRec; VAR f: ARRAY OF LONGINT; VAR caseTableSize: LONGINT): BOOLEAN;
  234. VAR tag: CHAR; i, num: LONGINT;
  235. BEGIN
  236. r.Char(tag);
  237. IF tag = 86X THEN (* links tag *)
  238. FOR i := 0 TO links-1 DO
  239. r.Char(tag); l[i].mod := ORD(tag);
  240. r.Char(tag); l[i].entry := ORD(tag);
  241. r.RawNum(num); l[i].link := num
  242. END;
  243. FOR i := 0 TO entries-1 DO
  244. r.RawNum(num); f[i] := num;
  245. END;
  246. r.RawNum(caseTableSize);
  247. RETURN TRUE
  248. ELSE
  249. RETURN FALSE
  250. END
  251. END ReadLinkBlock;
  252. (* ReadConstBlock - Read the constant block. *)
  253. PROCEDURE ReadConstBlock(r: Streams.Reader; m: Modules.Module; h: ObjHeader): BOOLEAN;
  254. VAR tag: CHAR; i: LONGINT; t: ADDRESS;
  255. BEGIN
  256. r.Char(tag);
  257. IF tag = 87X THEN (* constant tag *)
  258. t := m.sb;
  259. FOR i := 0 TO h.constSize-1 DO
  260. r.Char(tag); SYSTEM.PUT(t, tag); INC(t)
  261. END;
  262. SYSTEM.GET(m.sb, t); ASSERT(t = 0);
  263. SYSTEM.PUT(m.sb, m); (* SELF *)
  264. RETURN TRUE
  265. ELSE
  266. RETURN FALSE
  267. END
  268. END ReadConstBlock;
  269. (* ReadExportBlock - Read the export block. *)
  270. PROCEDURE ReadExportBlock(r: Streams.Reader; m: Modules.Module): BOOLEAN;
  271. TYPE ExportPtr = POINTER TO Modules.ExportDesc; (* this type is introduced to dereference fields of an ExportDesc variable *)
  272. VAR tag: CHAR; structs, i: LONGINT; struct: ARRAY MaxStructs OF ADDRESS;
  273. p {UNTRACED}: ExportPtr; (* this variable must be untraced since it will be casted from a pure address field, it is not a valid heap block *)
  274. PROCEDURE LoadScope(VAR scope: Modules.ExportDesc; level, adr: LONGINT);
  275. VAR no1, no2, fp, off, num: LONGINT;
  276. BEGIN
  277. r.RawLInt(num); scope.exports := num; (* fixed size *)
  278. no1 := 0; no2 := 0;
  279. IF scope.exports # 0 THEN
  280. NEW(scope.dsc, scope.exports);
  281. scope.dsc[0].adr := adr
  282. END;
  283. IF level = EUrecScope THEN
  284. INC(structs); struct[structs] := SYSTEM.VAL(ADDRESS, ADDRESSOF(scope))
  285. END;
  286. r.RawNum(fp);
  287. WHILE fp # EUEnd DO
  288. IF fp = EURecord THEN
  289. r.RawNum(off);
  290. IF off < 0 THEN
  291. p := SYSTEM.VAL(ExportPtr, struct[-off]);
  292. scope.dsc[no2].exports := p.exports;
  293. scope.dsc[no2].dsc := p.dsc (* old type *)
  294. ELSE
  295. LoadScope(scope.dsc[no2], EUrecScope, off)
  296. END
  297. ELSE
  298. IF level = EUobjScope THEN r.RawNum(adr); scope.dsc[no1].adr := adr END;
  299. scope.dsc[no1].fp := fp; no2 := no1; INC(no1)
  300. END;
  301. r.RawNum(fp)
  302. END
  303. END LoadScope;
  304. BEGIN
  305. r.Char(tag);
  306. IF tag = 88X THEN (* export tag *)
  307. structs := 0;
  308. FOR i := 0 TO MaxStructs - 1 DO struct[i] := Heaps.NilVal END;
  309. LoadScope(m.export, EUobjScope, 0);
  310. RETURN TRUE
  311. ELSE
  312. RETURN FALSE
  313. END
  314. END ReadExportBlock;
  315. (* ReadCodeBlock - Read the code block. *)
  316. PROCEDURE ReadCodeBlock(r: Streams.Reader; m: Modules.Module): BOOLEAN;
  317. VAR tag: CHAR; ignore: LONGINT;
  318. BEGIN
  319. r.Char(tag);
  320. IF tag = 89X THEN (* code tag *)
  321. r.Bytes(m.code^, 0, LEN(m.code), ignore);
  322. RETURN TRUE
  323. ELSE
  324. RETURN FALSE
  325. END
  326. END ReadCodeBlock;
  327. (* ReadUseBlock - Read and check the use block. *)
  328. PROCEDURE ReadUseBlock(r: Streams.Reader; m: Modules.Module; VAR dataLink: ARRAY OF DataLinkRec;
  329. VAR res: LONGINT; VAR msg: ARRAY OF CHAR): BOOLEAN;
  330. VAR tag: CHAR; i: LONGINT; name, prevname: ARRAY 256 OF CHAR; (*fof: not Modules.Name as name might consist of several identifiers, e.g. for methods *)
  331. mod: Modules.Module;
  332. PROCEDURE Err;
  333. BEGIN
  334. IF res = Ok THEN
  335. res := IncompatibleImport;
  336. COPY(m.name, msg); Modules.Append(" incompatible with ", msg); Modules.Append(mod.name, msg);
  337. END
  338. END Err;
  339. PROCEDURE FixupCall(code: ADDRESS; link: SIZE; fixval: ADDRESS);
  340. VAR nextlink: SIZE; opcode: CHAR;
  341. BEGIN
  342. REPEAT
  343. ASSERT((link >= 0) & (link < LEN(m.code)));
  344. SYSTEM.GET(code + link, nextlink);
  345. SYSTEM.GET(code + link - 1, opcode); (* backward disassembly safe? *)
  346. IF opcode = 0E8X THEN (* call instruction relative *)
  347. SYSTEM.PUT(code + link, fixval - (code + link + 4)) (* + 4: to next instruction *)
  348. (* relative, no further fixup required *)
  349. ELSE (* move instruction absolute *)
  350. SYSTEM.PUT(code + link, fixval)
  351. END;
  352. link := nextlink
  353. UNTIL link = Sentinel
  354. END FixupCall;
  355. PROCEDURE FixupVar(code: ADDRESS; link: SIZE; fixval: ADDRESS);
  356. VAR i: LONGINT; val, adr: ADDRESS;
  357. BEGIN
  358. ASSERT(dataLink[link].mod # 0); (* this must be non-local module (?) *)
  359. FOR i := 0 TO dataLink[link].fixups-1 DO
  360. adr := code + dataLink[link].ofs[i];
  361. SYSTEM.GET(adr, val); (* non-zero for example with constant index into imported array *)
  362. SYSTEM.PUT(adr, val + fixval)
  363. END
  364. END FixupVar;
  365. PROCEDURE CheckScope(scope: Modules.ExportDesc; level: LONGINT);
  366. VAR fp, i, link: LONGINT; adr: SIZE; tdadr: ADDRESS; tmpErr: BOOLEAN;
  367. BEGIN
  368. tmpErr := (level = EUerrScope);
  369. i := 0; link := 0;
  370. r.RawNum(fp);
  371. WHILE fp # EUEnd DO
  372. IF fp = EURecord THEN
  373. r.RawNum(link);
  374. IF tmpErr THEN
  375. CheckScope(scope.dsc[i], EUerrScope)
  376. ELSE
  377. IF scope.dsc[i].dsc # NIL THEN
  378. IF link # 0 THEN
  379. adr := scope.dsc[i].dsc[0].adr;
  380. SYSTEM.GET(mod.sb + adr, tdadr);
  381. SYSTEM.PUT(m.sb-link, tdadr) (* tdadr at tadr[0] *)
  382. END
  383. END;
  384. CheckScope(scope.dsc[i], EUrecScope)
  385. END
  386. ELSE
  387. prevname := name; ReadString8(r, name);
  388. IF level >= EUobjScope THEN
  389. tmpErr := FALSE;
  390. IF level = EUobjScope THEN r.RawNum(link) END;
  391. i := 0; WHILE (i < scope.exports) & (scope.dsc[i].fp # fp) DO INC(i) END;
  392. IF i >= scope.exports THEN
  393. Err; tmpErr := TRUE; Modules.Append("/", msg);
  394. IF name = "@" THEN Modules.Append("@/",msg); Modules.Append(prevname, msg)
  395. ELSE Modules.Append(name, msg)
  396. END;
  397. DEC(i)
  398. ELSIF (level = EUobjScope) & (link # 0) THEN
  399. IF ~(EUProcFlagBit IN SYSTEM.VAL(SET, link)) THEN
  400. FixupVar(ADDRESSOF(m.code[0]), link, mod.sb + scope.dsc[i].adr)
  401. ELSE
  402. FixupCall(ADDRESSOF(m.code[0]), SYSTEM.VAL(SIZE, SYSTEM.VAL(SET, link) - {EUProcFlagBit}),
  403. scope.dsc[i].adr + ADDRESSOF(mod.code[0]))
  404. END
  405. END
  406. END
  407. END;
  408. r.RawNum(fp)
  409. END
  410. END CheckScope;
  411. BEGIN
  412. r.Char(tag);
  413. IF tag = 8AX THEN (* use tag *)
  414. i := 0;
  415. ReadString8(r, name);
  416. WHILE (name # "") & (res = Ok) DO
  417. mod := Modules.ThisModule(name, res, msg);
  418. IF res = Ok THEN
  419. CheckScope(mod.export, EUobjScope)
  420. END;
  421. ReadString8(r, name)
  422. END
  423. ELSE
  424. res := FileCorrupt
  425. END;
  426. RETURN res = Ok
  427. END ReadUseBlock;
  428. (* ReadTypeBlock - Read the type block. *)
  429. PROCEDURE ReadTypeBlock(r: Streams.Reader; m: Modules.Module; VAR type: ARRAY OF TypeRec): BOOLEAN;
  430. VAR
  431. tag: CHAR; i, j, newMethods, pointers, method, entry, num: LONGINT;
  432. tdSize: LONGINT; (* ug *)
  433. recSize, ofs, totTdSize (* ug *): SIZE; base: ADDRESS;
  434. name: Modules.Name; flags: SET;
  435. startAddr, tdAdr: ADDRESS;
  436. staticTypeBlock {UNTRACED}: Heaps.StaticTypeBlock;
  437. BEGIN
  438. r.Char(tag);
  439. IF tag = 8BX THEN (* type tag *)
  440. totTdSize := 0;
  441. IF LEN(m.staticTypeDescs) > 0 THEN
  442. startAddr := ADDRESSOF(m.staticTypeDescs[0]);
  443. END;
  444. FOR i := 0 TO LEN(type)-1 DO
  445. type[i].init := FALSE;
  446. r.RawNum(num); recSize := num;
  447. r.RawNum(num); type[i].entry := num;
  448. r.RawNum(num); type[i].baseMod := num;
  449. r.RawNum(num); type[i].baseEntry := num;
  450. r.RawNum(num); type[i].methods := ABS (num);
  451. IF num >= 0 THEN flags := {} (* unprotected type *)
  452. ELSE flags := {Heaps.ProtTypeBit} (* protected type *)
  453. END;
  454. r.RawNum(num); type[i].inhMethods := num;
  455. r.RawNum(newMethods);
  456. r.RawLInt(pointers); (* fixed size *)
  457. r.RawString(name);
  458. r.RawLInt(tdSize); (* ug *)
  459. NEW(m.typeInfo[i]);
  460. Heaps.FillStaticType(tdAdr, startAddr, SYSTEM.VAL(ADDRESS, m.typeInfo[i]), tdSize, recSize, pointers,
  461. Modules.MaxTags + type[i].methods);
  462. m.typeInfo[i].tag := tdAdr;
  463. m.typeInfo[i].flags := flags;
  464. m.typeInfo[i].mod := m;
  465. m.typeInfo[i].name := name;
  466. base := m.typeInfo[i].tag + Modules.Mth0Ofs;
  467. FOR j := 0 TO newMethods - 1 DO
  468. r.RawNum(method);
  469. r.RawNum(entry);
  470. SYSTEM.PUT(base - AddressSize*method, m.entry[entry]);
  471. END;
  472. (* other methods are left NIL *)
  473. staticTypeBlock := SYSTEM.VAL(Heaps.StaticTypeBlock, tdAdr);
  474. ASSERT(LEN(staticTypeBlock.pointerOffsets) = pointers);
  475. FOR j := 0 TO pointers - 1 DO
  476. r.RawNum(num); ofs := num;
  477. ASSERT(ofs MOD AddressSize = 0); (* no deep copy flag *)
  478. staticTypeBlock.pointerOffsets[j] := ofs;
  479. ASSERT(ADDRESSOF(staticTypeBlock.pointerOffsets[j]) < startAddr + tdSize)
  480. END;
  481. ASSERT(m.typeInfo[i].tag # 0);
  482. ASSERT( (ADDRESSOF(m.data[0]) <= m.sb + type[i].entry) ,1001);
  483. ASSERT( (m.sb + type[i].entry+4 <= ADDRESSOF(m.data[LEN(m.data)-1])+1) ,1002 );
  484. SYSTEM.PUT(m.sb + type[i].entry, m.typeInfo[i].tag); (* patch in constant area *)
  485. startAddr := startAddr + tdSize;
  486. totTdSize := totTdSize + tdSize;
  487. END;
  488. ASSERT(totTdSize = LEN(m.staticTypeDescs));
  489. RETURN TRUE
  490. ELSE
  491. RETURN FALSE
  492. END
  493. END ReadTypeBlock;
  494. (* ReadRefBlock - Read the reference block. *)
  495. PROCEDURE ReadRefBlock(r: Streams.Reader; m: Modules.Module): BOOLEAN;
  496. VAR tag: CHAR; ignore: LONGINT;
  497. BEGIN
  498. r.Char(tag);
  499. IF tag = 8CX THEN (* ref tag *)
  500. r.Bytes(m.refs^, 0, LEN(m.refs), ignore);
  501. RETURN TRUE
  502. ELSE
  503. RETURN FALSE
  504. END
  505. END ReadRefBlock;
  506. (* FixupGlobals - Fix up references to global variables. *)
  507. PROCEDURE FixupGlobals(m: Modules.Module; VAR dataLink: ARRAY OF DataLinkRec);
  508. VAR i: LONGINT; t: SIZE; adr: ADDRESS;
  509. BEGIN
  510. IF dataLink[0].mod = 0 THEN (* local module has globals *)
  511. FOR i := 0 TO dataLink[0].fixups-1 DO
  512. adr := ADDRESSOF(m.code[0]) + dataLink[0].ofs[i];
  513. SYSTEM.GET(adr, t); SYSTEM.PUT(adr, t + m.sb)
  514. END
  515. END
  516. END FixupGlobals;
  517. (* FixupLinks - Fix up other references. *)
  518. PROCEDURE FixupLinks(m: Modules.Module; VAR link: ARRAY OF LinkRec; VAR fixupCounts: ARRAY OF LONGINT; caseTableSize: LONGINT; VAR res: LONGINT);
  519. VAR i: LONGINT;
  520. PROCEDURE FixRelative(ofs: SIZE; val: ADDRESS);
  521. VAR t: SIZE; adr: ADDRESS;
  522. BEGIN
  523. ASSERT(val # 0);
  524. WHILE ofs # Sentinel DO
  525. adr := ADDRESSOF(m.code[0])+ofs;
  526. SYSTEM.GET(adr, t);
  527. SYSTEM.PUT(adr, val - (adr+4)); (* fixup for relative CALL instruction => no relocation required *)
  528. ofs := t
  529. END
  530. END FixRelative;
  531. PROCEDURE FixEntry(ofs: SIZE; VAR fixupCounts: ARRAY OF LONGINT);
  532. VAR t: SIZE; adr: ADDRESS; i: LONGINT;
  533. BEGIN
  534. i := 0;
  535. WHILE ofs # Sentinel DO
  536. adr := ADDRESSOF(m.code[0])+ofs;
  537. SYSTEM.GET(adr, t);
  538. WHILE fixupCounts[i] = 0 DO INC(i) END;
  539. SYSTEM.PUT(adr, m.entry[i]);
  540. DEC(fixupCounts[i]);
  541. ofs := t
  542. END
  543. END FixEntry;
  544. PROCEDURE FixCase(ofs: SIZE; caseTableSize: LONGINT);
  545. VAR i: LONGINT; t: SIZE; adr: ADDRESS;
  546. BEGIN
  547. i := caseTableSize;
  548. WHILE i > 0 DO
  549. adr := m.sb+ofs;
  550. SYSTEM.GET(adr, t);
  551. SYSTEM.PUT(adr, ADDRESSOF(m.code[0]) + t);
  552. DEC(i); INC (ofs, AddressSize);
  553. END
  554. END FixCase;
  555. BEGIN
  556. FOR i := 0 TO LEN(link)-1 DO
  557. ASSERT(link[i].mod = 0); (* only fix local things *)
  558. CASE link[i].entry OF
  559. 243..253: HALT(100); (* not supported any more, replaced by direct call *)
  560. |254: FixEntry(link[i].link, fixupCounts) (* local procedure address *)
  561. |255: FixCase(link[i].link, caseTableSize) (* case table *)
  562. ELSE res := 3406; RETURN (* unknown fixup type *)
  563. END
  564. END
  565. END FixupLinks;
  566. (* When loader parsed the command block, the type descriptors have not yet been allocated so we could not fixup
  567. the addresses -> do it now. *)
  568. PROCEDURE FixupCommands(m : Modules.Module);
  569. VAR i : LONGINT;
  570. BEGIN
  571. FOR i := 0 TO LEN(m.command)-1 DO
  572. m.command[i].entryAdr := m.command[i].entryAdr + ADDRESSOF(m.code[0]);
  573. IF (m.command[i].argTdAdr > 1) THEN
  574. SYSTEM.GET(m.sb + m.command[i].argTdAdr, m.command[i].argTdAdr);
  575. END;
  576. IF (m.command[i].retTdAdr > 1) THEN
  577. SYSTEM.GET(m.sb + m.command[i].retTdAdr, m.command[i].retTdAdr);
  578. END;
  579. END;
  580. END FixupCommands;
  581. (* InitType - Initialize a dynamic type. *)
  582. PROCEDURE InitType(m: Modules.Module; VAR type: ARRAY OF TypeRec; i: LONGINT);
  583. VAR j, baseMod, extLevel: LONGINT; t: ADDRESS; root, baseTag, baseMth, baseRoot: ADDRESS; baseM: Modules.Module;
  584. BEGIN
  585. IF ~type[i].init THEN
  586. (* init type for dynamic type descriptors *)
  587. root := m.typeInfo[i].tag;
  588. baseTag := root + Modules.Tag0Ofs;
  589. baseMth := root + Modules.Mth0Ofs;
  590. baseMod := type[i].baseMod; extLevel := 0;
  591. ASSERT(baseMod >= -1);
  592. IF baseMod # -1 THEN (* extended type *)
  593. IF baseMod = 0 THEN (* base type local *)
  594. j := 0; WHILE type[j].entry # type[i].baseEntry DO INC(j) END; (* find base type *)
  595. InitType(m, type, j); (* and initialize it first *)
  596. baseM := m
  597. ELSE (* base type imported *)
  598. baseM := m.module[baseMod-1];
  599. t := type[i].baseEntry; (* fingerprint *)
  600. j := 0; WHILE baseM.export.dsc[j].fp # t DO INC(j) END; (* find base type *)
  601. type[i].baseEntry := baseM.export.dsc[j].dsc[0].adr
  602. END;
  603. (* copy base tags *)
  604. SYSTEM.GET(baseM.sb + type[i].baseEntry, baseRoot);
  605. SYSTEM.GET(baseRoot + Modules.Tag0Ofs, t);
  606. WHILE t # 0 DO
  607. SYSTEM.PUT(baseTag - AddressSize * extLevel, t);
  608. INC(extLevel);
  609. SYSTEM.GET(baseRoot + Modules.Tag0Ofs - AddressSize * extLevel, t)
  610. END;
  611. (* copy non-overwritten base methods *)
  612. FOR j := 0 TO type[i].inhMethods-1 DO
  613. SYSTEM.GET(baseMth - AddressSize * j, t); (* existing method *)
  614. IF t = 0 THEN
  615. SYSTEM.GET(baseRoot + Modules.Mth0Ofs - AddressSize*j, t); (* base method *)
  616. SYSTEM.PUT(baseMth - AddressSize * j, t)
  617. END;
  618. END
  619. END;
  620. m.typeInfo[i].flags := m.typeInfo[i].flags + SYSTEM.VAL(SET, extLevel);
  621. ASSERT(extLevel < Modules.MaxTags);
  622. SYSTEM.PUT(baseTag - AddressSize * extLevel, m.typeInfo[i].tag); (* self *)
  623. (* init type for static type descriptors *)
  624. type[i].init := TRUE
  625. END
  626. END InitType;
  627. PROCEDURE ReadExTableBlock(r: Streams.Reader; m: Modules.Module): BOOLEAN;
  628. VAR
  629. tag: CHAR;
  630. pcFrom, pcTo, pcHandler, i: LONGINT;
  631. PROCEDURE SelectionSort(exTable: Modules.ExceptionTable);
  632. VAR
  633. p, q, min: LONGINT;
  634. entry: Modules.ExceptionTableEntry;
  635. BEGIN
  636. FOR p := 0 TO LEN(exTable) - 2 DO
  637. min := p;
  638. FOR q := p + 1 TO LEN(exTable) - 1 DO
  639. IF exTable[min].pcFrom > exTable[q].pcFrom THEN min := q END;
  640. entry := exTable[min]; exTable[min] := exTable[p]; exTable[p] := entry;
  641. END
  642. END
  643. END SelectionSort;
  644. BEGIN
  645. r.Char(tag);
  646. IF tag = 8EX THEN
  647. FOR i := 0 TO LEN(m.exTable) -1 DO
  648. r.Char(tag);
  649. IF tag = 0FEX THEN
  650. r.RawNum(pcFrom);
  651. r.RawNum(pcTo);
  652. r.RawNum(pcHandler);
  653. m.exTable[i].pcFrom := pcFrom + ADDRESSOF(m.code[0]);
  654. m.exTable[i].pcTo := pcTo + ADDRESSOF(m.code[0]);
  655. m.exTable[i].pcHandler := pcHandler + ADDRESSOF(m.code[0]);
  656. ELSE
  657. RETURN FALSE;
  658. END;
  659. END;
  660. SelectionSort(m.exTable);
  661. RETURN TRUE;
  662. ELSE
  663. RETURN FALSE;
  664. END;
  665. END ReadExTableBlock;
  666. PROCEDURE ReadPtrsInProcBlock(r: Streams.Reader; m: Modules.Module): BOOLEAN;
  667. VAR tag: CHAR; i, j, codeoffset, beginOffset, endOffset, nofptrs, p : LONGINT;
  668. procTable: Modules.ProcTable; ptrTable: Modules.PtrTable;
  669. PROCEDURE Max(i, j : LONGINT) : LONGINT;
  670. BEGIN
  671. IF i > j THEN
  672. RETURN i
  673. ELSE
  674. RETURN j
  675. END
  676. END Max;
  677. PROCEDURE SwapProcTableEntries(p, q : LONGINT);
  678. VAR procentry : Modules.ProcTableEntry;
  679. k, i, basep, baseq: LONGINT; ptr: SIZE;
  680. BEGIN
  681. k := Max(procTable[p].noPtr, procTable[q].noPtr);
  682. IF k > 0 THEN (* swap entries in ptrTable first *)
  683. basep := p * m.maxPtrs; baseq := q * m.maxPtrs;
  684. FOR i := 0 TO k - 1 DO
  685. ptr := ptrTable[basep + i];
  686. ptrTable[basep + i] := ptrTable[baseq + i];
  687. ptrTable[baseq + i] := ptr
  688. END
  689. END;
  690. procentry := procTable[p];
  691. procTable[p] := procTable[q];
  692. procTable[q] := procentry
  693. END SwapProcTableEntries;
  694. PROCEDURE SortProcTable;
  695. VAR i, j, min : LONGINT;
  696. BEGIN
  697. FOR i := 0 TO m.noProcs - 2 DO
  698. min := i;
  699. FOR j := i + 1 TO m.noProcs - 1 DO
  700. IF procTable[j].pcFrom < procTable[min].pcFrom THEN min:= j END
  701. END;
  702. IF min # i THEN SwapProcTableEntries(i, min) END
  703. END
  704. END SortProcTable;
  705. BEGIN
  706. r.Char(tag);
  707. IF tag = 8FX THEN
  708. NEW(procTable, m.noProcs); NEW(ptrTable, m.noProcs * m.maxPtrs); (* m.noProcs > 0 since the empty module contains the module body procedure *)
  709. m.procTable := procTable; m.ptrTable := ptrTable;
  710. FOR i := 0 TO m.noProcs - 1 DO
  711. r.RawNum(codeoffset);
  712. r.RawNum(beginOffset);
  713. r.RawNum(endOffset);
  714. r.RawLInt(nofptrs); (* fixed size *)
  715. procTable[i].pcFrom := codeoffset + ADDRESSOF(m.code[0]);
  716. procTable[i].pcStatementBegin := beginOffset + ADDRESSOF(m.code[0]);
  717. procTable[i].pcStatementEnd := endOffset + ADDRESSOF(m.code[0]);
  718. procTable[i].noPtr := nofptrs;
  719. FOR j := 0 TO nofptrs - 1 DO
  720. r.RawNum(p);
  721. ptrTable[i * m.maxPtrs + j] := p
  722. END
  723. END;
  724. SortProcTable();
  725. m.firstProc := procTable[0].pcFrom;
  726. FOR i := 0 TO m.noProcs - 2 DO
  727. procTable[i].pcLimit := procTable[i + 1].pcFrom
  728. END;
  729. procTable[m.noProcs - 1].pcLimit := ADDRESSOF(m.code[0]) + LEN(m.code) + 1; (* last element reserved for end of code segment,
  730. allow 1 byte extra, cf. Modules.ThisModuleByAdr *)
  731. procTable := NIL; ptrTable := NIL;
  732. RETURN TRUE
  733. ELSE
  734. RETURN FALSE
  735. END
  736. END ReadPtrsInProcBlock;
  737. (** LoadObj - Load an Active Oberon object file. *)
  738. PROCEDURE LoadObj*(CONST name, fileName: ARRAY OF CHAR; VAR res: LONGINT; VAR msg: ARRAY OF CHAR): Modules.Module;
  739. VAR
  740. f: Files.File; r: Files.Reader; h: ObjHeader; m: Modules.Module; i, caseTableSize: LONGINT;
  741. dataLink: POINTER TO ARRAY OF DataLinkRec;
  742. link: POINTER TO ARRAY OF LinkRec;
  743. fixupCounts : POINTER TO ARRAY OF LONGINT;
  744. type: POINTER TO ARRAY OF TypeRec;
  745. BEGIN
  746. f := Files.Old(fileName);
  747. IF f # NIL THEN
  748. IF trace THEN KernelLog.String("Loading "); KernelLog.String(fileName); KernelLog.Ln END;
  749. res := Ok; msg[0] := 0X;
  750. Files.OpenReader(r, f, 0);
  751. ReadHeader(r, h, res, msg);
  752. IF res = Ok THEN
  753. IF h.name = name THEN
  754. NEW(m);
  755. i := 0; WHILE h.name[i] # 0X DO m.name[i] := h.name[i]; INC(i) END;
  756. m.name[i] := 0X;
  757. m.noProcs := h.procs;
  758. m.maxPtrs := h.maxPtrs;
  759. m.crc := h.crc;
  760. AllocateModule(m,h);
  761. IF trace THEN
  762. KernelLog.Hex(ADDRESSOF(m.code[0]), 8); KernelLog.Char(" ");
  763. KernelLog.String(m.name); KernelLog.Hex(m.sb, 9); KernelLog.Ln
  764. END;
  765. NEW(dataLink, h.dataLinks); NEW(link, h.links); NEW(fixupCounts, h.entries);
  766. NEW(type, h.types);
  767. IF ReadEntryBlock(r, m) & ReadCommandBlock(r, m) & ReadPointerBlock(r, m) &
  768. ReadImportBlock(r, m, res, msg) & ReadDataLinkBlock(r, h.dataLinks, dataLink^) &
  769. ReadLinkBlock(r, h.links, h.entries, link^, fixupCounts^, caseTableSize) & ReadConstBlock(r, m,h) & ReadExportBlock(r, m) &
  770. ReadCodeBlock(r, m) & ReadUseBlock(r, m, dataLink^, res, msg) &
  771. ReadTypeBlock(r, m, type^) & ReadExTableBlock(r, m) & ReadPtrsInProcBlock(r, m) &
  772. ReadRefBlock(r, m) THEN
  773. IF h.dataLinks # 0 THEN FixupGlobals(m, dataLink^) END;
  774. IF h.links # 0 THEN FixupLinks(m, link^, fixupCounts^, caseTableSize, res) END;
  775. IF h.commands # 0 THEN FixupCommands(m); END;
  776. IF res = Ok THEN
  777. FOR i := 0 TO LEN(type^)-1 DO InitType(m, type^, i) END
  778. END
  779. ELSE
  780. IF res = Ok THEN res := FileCorrupt END (* do not overwrite lower-level error code *)
  781. END;
  782. dataLink := NIL; link := NIL; type := NIL
  783. ELSE
  784. res := IncompatibleModuleName; COPY(fileName, msg); Modules.Append(" incompatible module name", msg)
  785. END;
  786. END;
  787. IF (res # Ok) & (msg[0] = 0X) THEN COPY(fileName, msg); Modules.Append(" corrupt", msg) END
  788. ELSE
  789. res := FileNotFound; COPY(fileName, msg); Modules.Append(" not found", msg)
  790. END;
  791. IF res # Ok THEN m := NIL END;
  792. RETURN m
  793. END LoadObj;
  794. PROCEDURE Trace*(context : Commands.Context);
  795. BEGIN
  796. trace := ~trace;
  797. context.out.String("Loader: trace ");
  798. IF trace THEN context.out.String("on") ELSE context.out.String("off") END;
  799. context.out.Ln;
  800. END Trace;
  801. PROCEDURE Init;
  802. VAR extension: ARRAY 32 OF CHAR;
  803. BEGIN
  804. trace := FALSE;
  805. Machine.GetConfig("ObjectFileExtension", extension);
  806. IF extension = "" THEN
  807. COPY(Machine.DefaultObjectFileExtension, extension)
  808. END;
  809. Modules.AddLoader(extension, LoadObj);
  810. END Init;
  811. BEGIN
  812. Init();
  813. END Loader.
  814. (*
  815. 11.05.98 pjm Started
  816. *)
  817. SystemTools.Free Loader ~