Loader.Mod 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646
  1. MODULE Loader; (** AUTHOR "fof"; PURPOSE "Object File Loader"; *)
  2. (* cf. Linker *)
  3. IMPORT SYSTEM, KernelLog, Modules, Streams, Files, D := KernelLog, GenericLinker, ObjectFile, Diagnostics, Strings, StringPool, Trace, Machine;
  4. CONST
  5. Ok = 0;
  6. LinkerError=3400;
  7. FileNotFound = 3401;
  8. CommandTrapped* = 3904; (* cf module Commands *)
  9. SupportOldObjectFileFormat = FALSE;
  10. TraceLoading = FALSE;
  11. TYPE
  12. HashEntryIntInt = RECORD
  13. key,value: SIZE;
  14. END;
  15. HashIntArray = POINTER TO ARRAY OF HashEntryIntInt;
  16. HashEntryIntAny = RECORD
  17. key: SIZE; value: ANY;
  18. END;
  19. HashIntAnyArray = POINTER TO ARRAY OF HashEntryIntAny;
  20. HashTableInt = OBJECT
  21. VAR
  22. table: HashIntArray;
  23. size: LONGINT;
  24. used-: LONGINT;
  25. maxLoadFactor: REAL;
  26. (* Interface *)
  27. PROCEDURE & Init* (initialSize: LONGINT);
  28. BEGIN
  29. ASSERT(initialSize > 2);
  30. NEW(table, initialSize);
  31. size := initialSize;
  32. used := 0;
  33. maxLoadFactor := 0.75;
  34. END Init;
  35. PROCEDURE Put*(key: SIZE; value: SIZE);
  36. VAR hash: SIZE;
  37. BEGIN
  38. ASSERT(key # 0);
  39. ASSERT(used < size);
  40. hash := HashValue(key);
  41. IF table[hash].key = 0 THEN
  42. INC(used, 1);
  43. END;
  44. table[hash].key := key;
  45. table[hash].value := value;
  46. IF (used / size) > maxLoadFactor THEN Grow END;
  47. END Put;
  48. PROCEDURE Get*(key: SIZE):SIZE;
  49. BEGIN
  50. RETURN table[HashValue(key)].value;
  51. END Get;
  52. PROCEDURE Has*(key: SIZE):BOOLEAN;
  53. BEGIN
  54. RETURN table[HashValue(key)].key = key;
  55. END Has;
  56. PROCEDURE Length*():LONGINT;
  57. BEGIN RETURN used; END Length;
  58. PROCEDURE Clear*;
  59. VAR i: LONGINT;
  60. BEGIN FOR i := 0 TO size - 1 DO table[i].key := 0; END; END Clear;
  61. (* Internals *)
  62. PROCEDURE HashValue(key: SIZE):SIZE;
  63. VAR value, h1, h2, i: SIZE;
  64. BEGIN
  65. i := 0;
  66. value := key;
  67. h1 := key MOD size;
  68. h2 := 1; (* Linear probing *)
  69. REPEAT
  70. value := (h1 + i*h2) MOD size;
  71. INC(i);
  72. UNTIL((table[value].key = 0) OR (table[value].key = key) OR (i > size));
  73. ASSERT((table[value].key = 0) OR (table[value].key = key));
  74. RETURN value;
  75. END HashValue;
  76. PROCEDURE Grow;
  77. VAR oldTable: HashIntArray; oldSize, i, key: SIZE;
  78. BEGIN
  79. oldSize := size;
  80. oldTable := table;
  81. Init(size*2);
  82. FOR i := 0 TO oldSize-1 DO
  83. key := oldTable[i].key;
  84. IF key # 0 THEN
  85. Put(key, oldTable[i].value);
  86. END;
  87. END;
  88. END Grow;
  89. END HashTableInt;
  90. HashTableIntAny* = OBJECT
  91. VAR
  92. table: HashIntAnyArray;
  93. size: LONGINT;
  94. used-: LONGINT;
  95. maxLoadFactor: REAL;
  96. (* Interface *)
  97. PROCEDURE & Init* (initialSize: LONGINT);
  98. BEGIN
  99. ASSERT(initialSize > 2);
  100. NEW(table, initialSize);
  101. size := initialSize;
  102. used := 0;
  103. maxLoadFactor := 0.75;
  104. END Init;
  105. PROCEDURE Put*(key: SIZE; value: ANY);
  106. VAR hash: SIZE;
  107. BEGIN
  108. ASSERT(key # 0);
  109. ASSERT(used < size);
  110. hash := HashValue(key);
  111. IF table[hash].key = 0 THEN
  112. INC(used, 1);
  113. END;
  114. table[hash].key := key;
  115. table[hash].value := value;
  116. IF (used / size) > maxLoadFactor THEN Grow END;
  117. END Put;
  118. PROCEDURE Get*(key: SIZE):ANY;
  119. BEGIN
  120. RETURN table[HashValue(key)].value;
  121. END Get;
  122. PROCEDURE Has*(key: SIZE):BOOLEAN;
  123. BEGIN
  124. RETURN table[HashValue(key)].key = key;
  125. END Has;
  126. PROCEDURE Length*():LONGINT;
  127. BEGIN RETURN used; END Length;
  128. PROCEDURE Clear*;
  129. VAR i: LONGINT;
  130. BEGIN FOR i := 0 TO size - 1 DO table[i].key := 0; END; END Clear;
  131. (* Interface for integer values *)
  132. (* Internals *)
  133. PROCEDURE HashValue(key: SIZE):SIZE;
  134. VAR value, h1, h2, i:SIZE;
  135. BEGIN
  136. i := 0;
  137. value := key;
  138. h1 := key MOD size;
  139. h2 := 1; (* Linear probing *)
  140. REPEAT
  141. value := (h1 + i*h2) MOD size;
  142. INC(i);
  143. UNTIL((table[value].key = 0) OR (table[value].key = key) OR (i > size));
  144. ASSERT((table[value].key = 0) OR (table[value].key = key));
  145. RETURN value;
  146. END HashValue;
  147. PROCEDURE Grow;
  148. VAR oldTable: HashIntAnyArray; oldSize, i, key: SIZE;
  149. BEGIN
  150. oldSize := size;
  151. oldTable := table;
  152. Init(size*2);
  153. FOR i := 0 TO oldSize-1 DO
  154. key := oldTable[i].key;
  155. IF key # 0 THEN
  156. Put(key, oldTable[i].value);
  157. END;
  158. END;
  159. END Grow;
  160. END HashTableIntAny;
  161. Data=RECORD size, pos: LONGINT; bytes: Modules.Bytes; firstAddress: ADDRESS; END;
  162. Arrangement* = OBJECT (GenericLinker.Arrangement);
  163. VAR
  164. code, data: Data;
  165. (*moduleAdr: LONGINT;*)
  166. hasBody: BOOLEAN;
  167. bodyAddress : ADDRESS;
  168. PROCEDURE & InitArrangement;
  169. BEGIN InitData(code); InitData(data); hasBody := FALSE;
  170. END InitArrangement;
  171. PROCEDURE Preallocate*(CONST section: ObjectFile.Section);
  172. BEGIN
  173. ASSERT(section.unit = 8);
  174. ASSERT(section.bits.GetSize() MOD 8 = 0);
  175. ASSERT(section.type # ObjectFile.InitCode);
  176. IF section.type IN {ObjectFile.Code, ObjectFile.BodyCode} THEN
  177. DoPreallocate(section, code);
  178. ELSE ASSERT (section.type IN {ObjectFile.Const, ObjectFile.Data});
  179. DoPreallocate(section, data);
  180. END;
  181. END Preallocate;
  182. PROCEDURE Allocate* (CONST section: ObjectFile.Section): GenericLinker.Address;
  183. VAR adr: GenericLinker.Address;
  184. BEGIN
  185. IF section.type IN {ObjectFile.Code, ObjectFile.BodyCode} THEN
  186. adr := DoAllocate(section, code);
  187. ELSE ASSERT(section.type IN {ObjectFile.Const, ObjectFile.Data});
  188. adr := DoAllocate(section, data);
  189. END;
  190. IF section.type = ObjectFile.BodyCode THEN
  191. hasBody := TRUE; bodyAddress := adr;
  192. END;
  193. (*
  194. IF (section.identifier.name[0] >= 0) & (section.identifier.name[1] >= 0) THEN
  195. IF (section.identifier.name[1] = InternalModuleName) OR (section.identifier.name[2] = InternalModuleName) THEN
  196. moduleAdr := adr
  197. END;
  198. END;
  199. *)
  200. RETURN adr;
  201. END Allocate;
  202. PROCEDURE Patch* (pos, value: GenericLinker.Address; offset, bits, unit: ObjectFile.Bits);
  203. VAR char: CHAR;
  204. BEGIN
  205. ASSERT(bits MOD 8 = 0);
  206. ASSERT(unit = 8);
  207. WHILE bits > 0 DO
  208. char := CHR(value);
  209. SYSTEM.PUT(pos, char);
  210. value := value DIV 256;
  211. DEC(bits,8); INC(pos,1);
  212. END;
  213. END Patch;
  214. END Arrangement;
  215. ModuleList=OBJECT
  216. VAR
  217. hash: HashTableIntAny;
  218. PROCEDURE &Init;
  219. BEGIN
  220. NEW(hash,128);
  221. END Init;
  222. PROCEDURE ThisModule(module: Modules.Module): HashTableInt;
  223. VAR modList: HashTableInt;
  224. any: ANY;
  225. PROCEDURE TraverseScopes(CONST scope: Modules.ExportDesc; level: LONGINT);
  226. VAR adr: ADDRESS; i: LONGINT;
  227. BEGIN
  228. IF (level > 2) THEN RETURN END;
  229. IF (scope.fp # 0) THEN
  230. adr := scope.adr;
  231. IF SupportOldObjectFileFormat THEN
  232. IF module.staticTypeDescs # testTypeDescs THEN (* old object file format *)
  233. IF (adr = 0) & (scope.exports > 0) THEN (* type in old object file format *)
  234. adr := scope.dsc[0].adr;
  235. SYSTEM.GET(module.sb + adr, adr);
  236. ELSIF adr # 0 THEN
  237. INC(adr,ADDRESSOF(module.code[0]));
  238. END;
  239. END;
  240. END;
  241. modList.Put(SIZE(scope.fp), adr)
  242. END;
  243. FOR i := 0 TO scope.exports-1 DO
  244. IF scope.dsc # NIL THEN TraverseScopes(scope.dsc[i],level+1) END;
  245. END;
  246. adr := 0;
  247. END TraverseScopes;
  248. BEGIN{EXCLUSIVE}
  249. IF hash.Has(SYSTEM.VAL(SIZE, module)) THEN
  250. any := hash.Get(SYSTEM.VAL(SIZE,module));
  251. modList := any(HashTableInt);
  252. ELSE
  253. NEW(modList,256); TraverseScopes(module.export,0);
  254. hash.Put(SYSTEM.VAL(SIZE,module), modList);
  255. RETURN modList
  256. END;
  257. RETURN modList;
  258. END ThisModule;
  259. END ModuleList;
  260. Linker = OBJECT (GenericLinker.Linker)
  261. VAR
  262. moduleName: ObjectFile.SegmentedName;
  263. importBlock: GenericLinker.Block;
  264. hash: HashTableIntAny;
  265. moduleBlock: GenericLinker.Block;
  266. PROCEDURE &InitLinkerX* (diagnostics: Diagnostics.Diagnostics; log: Streams.Writer; code, data: GenericLinker.Arrangement; CONST name: ARRAY OF CHAR);
  267. BEGIN
  268. ObjectFile.StringToSegmentedName(name, moduleName);
  269. InitLinker(diagnostics, log, GenericLinker.UseAllButInitCode (* strip init code *), code, data);
  270. NEW(importBlock);
  271. NEW(hash,256); (* hash for blocks *)
  272. END InitLinkerX;
  273. (* oerwritten functionality of generic linker *)
  274. PROCEDURE FindBlock*(CONST identifier: ObjectFile.Identifier): GenericLinker.Block;
  275. VAR block: GenericLinker.Block; any: ANY;
  276. BEGIN
  277. block := NIL;
  278. IF IsPrefix(moduleName, identifier.name) THEN (* local block *)
  279. IF identifier.fingerprint = 0 THEN (* not identifiable via fingerprint *)
  280. block := FindBlock^(identifier);
  281. ELSE
  282. any := hash.Get(SYSTEM.VAL(SIZE, identifier.fingerprint));
  283. IF any # NIL THEN block := any(GenericLinker.Block) (* local block *) END;
  284. IF (block # NIL) & (block.identifier.name # identifier.name) THEN (* local block, false or duplicate fingerprint *)
  285. block := FindBlock^(identifier)
  286. END;
  287. END;
  288. END;
  289. RETURN block;
  290. END FindBlock;
  291. PROCEDURE ExportBlock*(block: GenericLinker.Block);
  292. BEGIN
  293. IF block.identifier.fingerprint # 0 THEN
  294. hash.Put(SYSTEM.VAL(SIZE, block.identifier.fingerprint), block)
  295. END;
  296. IF (block.identifier.name[0] >= 0) & (block.identifier.name[1] >= 0) THEN
  297. IF (block.identifier.name[1] = InternalModuleName) & (block.identifier.name[2]<0) OR (block.identifier.name[2] = InternalModuleName) & (block.identifier.name[3] < 0) THEN
  298. moduleBlock := block;
  299. END;
  300. END;
  301. END ExportBlock;
  302. PROCEDURE ImportBlock*(CONST fixup: ObjectFile.Fixup): GenericLinker.Block;
  303. VAR name: Modules.Name; res: WORD;
  304. msg: ARRAY 128 OF CHAR; module: Modules.Module; adr: ADDRESS; m: HashTableInt;
  305. s: ObjectFile.SectionName; isModule: BOOLEAN; identifier: ObjectFile.Identifier;
  306. fp: HUGEINT;
  307. PROCEDURE CheckName(n: StringPool.Index; name {UNTRACED}: Modules.DynamicName): LONGINT;
  308. VAR s: ObjectFile.SectionName; i: LONGINT;
  309. BEGIN
  310. IF name = NIL THEN RETURN -1 END;
  311. StringPool.GetString(n, s);
  312. i := 0;
  313. WHILE (s[i] # 0X) & (name[i] # 0X) & (s[i] = name[i]) DO
  314. INC(i);
  315. END;
  316. RETURN ORD(s[i]) - ORD(name[i]);
  317. END CheckName;
  318. PROCEDURE Error(n: StringPool.Index);
  319. VAR name: ARRAY 256 OF CHAR;
  320. BEGIN
  321. StringPool.GetString(n, name);
  322. TRACE("Fingerprint does not match",name);
  323. END Error;
  324. (* stupid implementation: just search for fp in all exports *)
  325. PROCEDURE CheckScope(CONST scope: Modules.ExportDesc; level: LONGINT): ADDRESS;
  326. VAR adr,lo,hi,m,res: SIZE;
  327. BEGIN
  328. adr := 0;
  329. (* export names are sorted, binary search: *)
  330. lo := 0; hi := scope.exports-1;
  331. WHILE (lo <= hi) DO
  332. m := (lo + hi) DIV 2;
  333. res := CheckName(identifier.name[level], scope.dsc[m].name);
  334. IF res = 0 THEN
  335. IF (level = LEN(identifier.name)-1) OR (identifier.name[level+1] <= 0) THEN
  336. (*IF (scope.dsc[m].fp # identifier.fingerprint) & (scope.dsc[m].fp # 0) & (identifier.fingerprint # 0) THEN
  337. Error(identifier.name[level]);
  338. END;
  339. *)
  340. fp := scope.dsc[m].fp;
  341. RETURN scope.dsc[m].adr
  342. ELSE
  343. RETURN CheckScope(scope.dsc[m], level+1);
  344. END;
  345. ELSIF res > 0 THEN lo := m+1;
  346. ELSE hi := m-1;
  347. END;
  348. END;
  349. RETURN 0;
  350. END CheckScope;
  351. BEGIN
  352. identifier := fixup.identifier;
  353. IF IsPrefix(moduleName, identifier.name) THEN
  354. D.String("circular import while trying to fetch ");
  355. s := identifier.name; D.String(s);
  356. D.Ln;
  357. RETURN NIL
  358. END;
  359. StringPool.GetString(identifier.name[0], name);
  360. isModule := identifier.name[1] = InternalModuleName;
  361. (*
  362. IF ~isModule & (identifier.fingerprint = 0) THEN
  363. D.String("Invalid attempt to import symbol without fingerprint ");
  364. s := identifier.name; D.String(s);
  365. D.Ln;
  366. RETURN NIL
  367. END;
  368. *)
  369. module := Modules.ThisModule(name,res,msg);
  370. IF module = NIL THEN
  371. D.String("could not get module while importing "); D.String(name); D.Ln;
  372. RETURN NIL
  373. END;
  374. IF isModule THEN
  375. adr := SYSTEM.VAL(ADDRESS, module) - fixup.patch[0].displacement;
  376. ELSE
  377. m := moduleList.ThisModule(module);
  378. ASSERT(module # NIL);
  379. (* first try via hash-table *)
  380. (* disabled -- might be able to remove hash table completely, needs some testing
  381. IF identifier.fingerprint # 0 THEN
  382. adr := m.Get(identifier.fingerprint);
  383. END;
  384. *)
  385. (* if it does not work, then try export table directly *)
  386. IF adr = 0 THEN
  387. adr := CheckScope(module.export,1(*level*) );
  388. END;
  389. END;
  390. IF adr = 0 THEN
  391. (*D.String("Loader Fatal error: did not find block "); s := identifier.name; D.String(s); D.Ln;*)
  392. RETURN NIL;
  393. ELSE (* found *)
  394. importBlock.identifier.fingerprint := fp; importBlock.address := adr
  395. END;
  396. RETURN importBlock
  397. END ImportBlock;
  398. END Linker;
  399. VAR
  400. moduleList: ModuleList;
  401. testTypeDescs: Modules.Bytes;
  402. InternalModuleName: StringPool.Index;
  403. PROCEDURE InitData(VAR data: Data);
  404. BEGIN
  405. data.pos := 0; data.size := 0; data.bytes := NIL; data.firstAddress := 0;
  406. END InitData;
  407. PROCEDURE IsPrefix(CONST prefix, of: ObjectFile.SegmentedName): BOOLEAN;
  408. VAR prefixS, ofS: ObjectFile.SectionName; i: LONGINT;
  409. BEGIN
  410. i := 0;
  411. WHILE (i< LEN(prefix)) & (prefix[i] = of[i]) DO INC(i) END;
  412. IF i = LEN(prefix) THEN RETURN TRUE (* identical *)
  413. ELSE (* prefix[i] # of[i] *)
  414. IF prefix[i] < 0 THEN RETURN TRUE (* name longer than prefix *)
  415. ELSIF of[i] < 0 THEN RETURN FALSE (* prefix longer than name *)
  416. ELSIF (i<LEN(prefix)-1) THEN RETURN FALSE (* prefix and name differ but not at the tail *)
  417. ELSE
  418. (* check tail *)
  419. StringPool.GetString(prefix[i], prefixS);
  420. StringPool.GetString(of[i], ofS);
  421. RETURN Strings.StartsWith(prefixS, 0, ofS)
  422. END
  423. END;
  424. END IsPrefix;
  425. PROCEDURE DoPreallocate(CONST section: ObjectFile.Section; VAR data: Data);
  426. BEGIN
  427. ASSERT(section.bits.GetSize() MOD 8 = 0);
  428. IF section.alignment > 0 THEN
  429. INC(data.size, (-data.size) MOD section.alignment); (* here we assume that base-alignment is ok *)
  430. END;
  431. INC(data.size, section.bits.GetSize() DIV 8);
  432. END DoPreallocate;
  433. PROCEDURE DoAllocate(CONST section: ObjectFile.Section; VAR data: Data): ADDRESS;
  434. VAR address: ADDRESS; size: SIZE;
  435. BEGIN
  436. IF (data.bytes = NIL) OR (LEN(data.bytes) # data.size) THEN NEW(data.bytes, data.size) END;
  437. IF section.alignment > 0 THEN
  438. INC(data.pos, (-data.pos) MOD section.alignment); (* here we assume that base-alignment is ok *)
  439. END;
  440. address := ADDRESSOF(data.bytes[0])+data.pos; (* to account for potentially empty variable at end of data ... *)
  441. size := section.bits.GetSize();
  442. section.bits.CopyTo(address, size);
  443. INC(data.pos, LONGINT(size DIV 8));
  444. (*
  445. bitPos:= 0;
  446. WHILE size > 0 DO
  447. value := section.bits.GetBits(bitPos,8);
  448. data.bytes[data.pos] := CHR(value);
  449. DEC(size,8); INC(data.pos); INC(bitPos,8);
  450. END;
  451. *)
  452. IF data.firstAddress = 0 THEN data.firstAddress := address END;
  453. RETURN address
  454. END DoAllocate;
  455. PROCEDURE LoadObj*(CONST name, fileName: ARRAY OF CHAR; VAR res: WORD; VAR msg: ARRAY OF CHAR): Modules.Module;
  456. TYPE Body=PROCEDURE;
  457. VAR
  458. file: Files.File; reader: Files.Reader; linker: Linker;
  459. arrangement: Arrangement; diagnostics: Diagnostics.StreamDiagnostics; stringWriter: Streams.StringWriter;
  460. module: Modules.Module; heapBlockAdr,moduleAdr: ADDRESS;
  461. Log: Streams.Writer;
  462. BEGIN
  463. file := Files.Old(fileName);
  464. IF file # NIL THEN
  465. IF TraceLoading THEN Trace.String("loading"); Trace.String(fileName); Trace.Ln END;
  466. res := Ok; msg[0] := 0X;
  467. Files.OpenReader(reader, file, 0);
  468. NEW(arrangement); NEW(stringWriter,256);
  469. Streams.OpenWriter( Log, KernelLog.Send );
  470. NEW(diagnostics,Log);
  471. NEW(linker, diagnostics, NIL, arrangement, arrangement,name);
  472. IF TraceLoading THEN Trace.String("before linking"); Trace.Ln END;
  473. GenericLinker.Process (reader, linker);
  474. IF ~linker.error THEN linker.Resolve END;
  475. IF ~linker.error THEN linker.Link END;
  476. (*D.Update;*)
  477. IF ~linker.error THEN
  478. IF TraceLoading THEN Trace.String("linking done"); Trace.Ln END;
  479. moduleAdr := linker.moduleBlock.address;
  480. IF ~Machine.IsCooperative THEN
  481. SYSTEM.GET(moduleAdr+2*SIZEOF(ADDRESS)+2*SIZEOF(WORD), moduleAdr);
  482. SYSTEM.GET(moduleAdr-2*SIZEOF(ADDRESS), heapBlockAdr);
  483. ASSERT(heapBlockAdr = linker.moduleBlock.address+2*SIZEOF(ADDRESS));
  484. END;
  485. module := SYSTEM.VAL(Modules.Module,moduleAdr);
  486. module.staticTypeDescs := testTypeDescs; (* trick to identify new object file loaded modules *)
  487. module.data := arrangement.data.bytes;
  488. module.code := arrangement.code.bytes;
  489. module.sb := 0 (*arrangement.data.firstAddress*); (* zero is correct ! *)
  490. module.body := SYSTEM.VAL(Body, arrangement.bodyAddress);
  491. (*
  492. SortProcTable(module);
  493. SelectionSort(module.exTable);
  494. *)
  495. (*
  496. careful: when GC uses a heuristic for pointer detection on the stack, it will not
  497. trace the module because the module is not reachable as a heap block in a sweep
  498. Therefore the code and data array has to be secured in addition.
  499. Here this is made sure to enter the module in the data structure before returning it.
  500. *)
  501. Modules.Initialize(module);
  502. ELSE module := NIL; res := LinkerError; stringWriter.Update; stringWriter.Get(msg);
  503. END;
  504. ELSE
  505. res := FileNotFound; COPY(fileName, msg); Modules.Append(" not found", msg)
  506. END;
  507. IF res # Ok THEN module := NIL END;
  508. IF (res # Ok) & (res # FileNotFound) THEN D.String(msg);D.Ln END;
  509. RETURN module
  510. FINALLY
  511. res := CommandTrapped;
  512. RETURN NIL
  513. END LoadObj;
  514. PROCEDURE Install*;
  515. VAR extension: ARRAY 32 OF CHAR;
  516. BEGIN
  517. Machine.GetConfig("ObjectFileExtension", extension);
  518. IF extension = "" THEN
  519. COPY(Machine.DefaultObjectFileExtension, extension)
  520. END;
  521. Modules.AddLoader(extension, LoadObj);
  522. END Install;
  523. PROCEDURE Remove*;
  524. VAR extension: ARRAY 32 OF CHAR;
  525. BEGIN
  526. Machine.GetConfig("ObjectFileExtension", extension);
  527. IF extension = "" THEN
  528. COPY(Machine.DefaultObjectFileExtension, extension)
  529. END;
  530. Modules.RemoveLoader(extension,LoadObj);
  531. END Remove;
  532. BEGIN
  533. NEW(testTypeDescs,1);
  534. Modules.InstallTermHandler(Remove);
  535. StringPool.GetIndex("@Module",InternalModuleName);
  536. NEW(moduleList);
  537. Install;
  538. END Loader.
  539. (* concurrent load test:
  540. VAR
  541. startConcurrentLoad: BOOLEAN;
  542. PROCEDURE ConcurrentLoad*;
  543. VAR i: LONGINT;
  544. o: OBJECT VAR
  545. mod: Modules.Module; res: WORD; msg: ARRAY 32 OF CHAR;
  546. BEGIN{ACTIVE}
  547. WHILE(~startConcurrentLoad) DO END;
  548. mod := Modules.ThisModule("Test",res,msg);
  549. END;
  550. BEGIN
  551. startConcurrentLoad := FALSE;
  552. FOR i := 0 TO 128 DO
  553. NEW(o);
  554. END;
  555. startConcurrentLoad := TRUE;
  556. END ConcurrentLoad;
  557. *)