GenericLoader.Mod 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646
  1. MODULE GenericLoader; (** AUTHOR "fof"; PURPOSE "Active Oberon Generic 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: LONGINT;
  14. END;
  15. HashIntArray = POINTER TO ARRAY OF HashEntryIntInt;
  16. HashEntryIntAny = RECORD
  17. key: LONGINT; 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: LONGINT; value: LONGINT);
  36. VAR hash: LONGINT;
  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: LONGINT):LONGINT;
  49. BEGIN
  50. RETURN table[HashValue(key)].value;
  51. END Get;
  52. PROCEDURE Has*(key: LONGINT):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: LONGINT):LONGINT;
  63. VAR value, h1, h2, i: LONGINT;
  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: LONGINT;
  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: LONGINT; value: ANY);
  106. VAR hash: LONGINT;
  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: LONGINT):ANY;
  119. BEGIN
  120. RETURN table[HashValue(key)].value;
  121. END Get;
  122. PROCEDURE Has*(key: LONGINT):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: LONGINT):LONGINT;
  134. VAR value, h1, h2, i: LONGINT;
  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: LONGINT;
  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: LONGINT; END;
  162. Arrangement* = OBJECT (GenericLinker.Arrangement);
  163. VAR
  164. code, data: Data;
  165. (*moduleAdr: LONGINT;*)
  166. hasBody: BOOLEAN;
  167. bodyAddress : LONGINT;
  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,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(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(LONGINT, module)) THEN
  250. any := hash.Get(SYSTEM.VAL(LONGINT,module));
  251. modList := any(HashTableInt);
  252. ELSE
  253. NEW(modList,256); TraverseScopes(module.export,0);
  254. hash.Put(SYSTEM.VAL(LONGINT,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(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(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: LONGINT;
  304. msg: ARRAY 128 OF CHAR; module: Modules.Module; adr: LONGINT; m: HashTableInt;
  305. s: ObjectFile.SectionName; isModule: BOOLEAN; identifier: ObjectFile.Identifier;
  306. PROCEDURE CheckName(n: StringPool.Index; name {UNTRACED}: Modules.DynamicName): LONGINT;
  307. VAR s: ObjectFile.SectionName; i: LONGINT;
  308. BEGIN
  309. IF name = NIL THEN RETURN -1 END;
  310. StringPool.GetString(n, s);
  311. i := 0;
  312. WHILE (s[i] # 0X) & (name[i] # 0X) & (s[i] = name[i]) DO
  313. INC(i);
  314. END;
  315. RETURN ORD(s[i]) - ORD(name[i]);
  316. END CheckName;
  317. PROCEDURE Error(n: StringPool.Index);
  318. VAR name: ARRAY 256 OF CHAR;
  319. BEGIN
  320. StringPool.GetString(n, name);
  321. TRACE("Fingerprint does not match",name);
  322. END Error;
  323. (* stupid implementation: just search for fp in all exports *)
  324. PROCEDURE CheckScope(CONST scope: Modules.ExportDesc; level: LONGINT): LONGINT;
  325. VAR adr,lo,hi,m,res: LONGINT;
  326. BEGIN
  327. adr := 0;
  328. (* export names are sorted, binary search: *)
  329. lo := 0; hi := scope.exports-1;
  330. WHILE (lo <= hi) DO
  331. m := (lo + hi) DIV 2;
  332. res := CheckName(identifier.name[level], scope.dsc[m].name);
  333. IF res = 0 THEN
  334. IF (level = LEN(identifier.name)-1) OR (identifier.name[level+1] <= 0) THEN
  335. IF (scope.dsc[m].fp # identifier.fingerprint) & (scope.dsc[m].fp # 0) & (identifier.fingerprint # 0) THEN
  336. Error(identifier.name[level]);
  337. RETURN 0;
  338. END;
  339. RETURN scope.dsc[m].adr
  340. ELSE
  341. RETURN CheckScope(scope.dsc[m], level+1);
  342. END;
  343. ELSIF res > 0 THEN lo := m+1;
  344. ELSE hi := m-1;
  345. END;
  346. END;
  347. RETURN 0;
  348. END CheckScope;
  349. BEGIN
  350. identifier := fixup.identifier;
  351. IF IsPrefix(moduleName, identifier.name) THEN
  352. D.String("circular import while trying to fetch ");
  353. s := identifier.name; D.String(s);
  354. D.Ln;
  355. RETURN NIL
  356. END;
  357. StringPool.GetString(identifier.name[0], name);
  358. isModule := identifier.name[1] = InternalModuleName;
  359. IF (identifier.name[0] = OberonName) & (identifier.name[2] >= 0) THEN (* in Oberon name space *)
  360. StringPool.GetString(identifier.name[1], s);
  361. Strings.Append(name, ".");
  362. Strings.Append(name, s);
  363. isModule := identifier.name[2] = InternalModuleName;
  364. END;
  365. (*
  366. IF ~isModule & (identifier.fingerprint = 0) THEN
  367. D.String("Invalid attempt to import symbol without fingerprint ");
  368. s := identifier.name; D.String(s);
  369. D.Ln;
  370. RETURN NIL
  371. END;
  372. *)
  373. module := Modules.ThisModule(name,res,msg);
  374. IF module = NIL THEN
  375. D.String("could not get module while importing "); D.String(name); D.Ln;
  376. RETURN NIL
  377. END;
  378. IF isModule THEN
  379. adr := SYSTEM.VAL(ADDRESS, module) - fixup.patch[0].displacement;
  380. ELSE
  381. m := moduleList.ThisModule(module);
  382. ASSERT(module # NIL);
  383. (* first try via hash-table *)
  384. (* disabled -- might be able to remove hash table completely, needs some testing
  385. IF identifier.fingerprint # 0 THEN
  386. adr := m.Get(identifier.fingerprint);
  387. END;
  388. *)
  389. (* if it does not work, then try export table directly *)
  390. IF adr = 0 THEN
  391. adr := CheckScope(module.export,1(*level*) );
  392. END;
  393. END;
  394. IF adr = 0 THEN
  395. D.String("GenericLoader Fatal error: did not find block "); s := identifier.name; D.String(s); D.Ln;
  396. RETURN NIL;
  397. ELSE (* found *)
  398. importBlock.identifier.fingerprint := identifier.fingerprint; importBlock.address := adr
  399. END;
  400. RETURN importBlock
  401. END ImportBlock;
  402. END Linker;
  403. VAR
  404. moduleList: ModuleList;
  405. testTypeDescs: Modules.Bytes;
  406. InternalModuleName, OberonName: StringPool.Index;
  407. PROCEDURE InitData(VAR data: Data);
  408. BEGIN
  409. data.pos := 0; data.size := 0; data.bytes := NIL; data.firstAddress := 0;
  410. END InitData;
  411. PROCEDURE IsPrefix(CONST prefix, of: ObjectFile.SegmentedName): BOOLEAN;
  412. VAR prefixS, ofS: ObjectFile.SectionName; i: LONGINT;
  413. BEGIN
  414. i := 0;
  415. WHILE (i< LEN(prefix)) & (prefix[i] = of[i]) DO INC(i) END;
  416. IF i = LEN(prefix) THEN RETURN TRUE (* identical *)
  417. ELSE (* prefix[i] # of[i] *)
  418. IF prefix[i] < 0 THEN RETURN TRUE (* name longer than prefix *)
  419. ELSIF of[i] < 0 THEN RETURN FALSE (* prefix longer than name *)
  420. ELSIF (i<LEN(prefix)-1) THEN RETURN FALSE (* prefix and name differ but not at the tail *)
  421. ELSE
  422. (* check tail *)
  423. StringPool.GetString(prefix[i], prefixS);
  424. StringPool.GetString(of[i], ofS);
  425. RETURN Strings.StartsWith(prefixS, 0, ofS)
  426. END
  427. END;
  428. END IsPrefix;
  429. PROCEDURE DoPreallocate(CONST section: ObjectFile.Section; VAR data: Data);
  430. BEGIN
  431. ASSERT(section.bits.GetSize() MOD 8 = 0);
  432. IF section.alignment > 0 THEN
  433. INC(data.size, (-data.size) MOD section.alignment); (* here we assume that base-alignment is ok *)
  434. END;
  435. INC(data.size, section.bits.GetSize() DIV 8);
  436. END DoPreallocate;
  437. PROCEDURE DoAllocate(CONST section: ObjectFile.Section; VAR data: Data): GenericLinker.Address;
  438. VAR address: ObjectFile.Bits; size: SIZE;
  439. BEGIN
  440. IF (data.bytes = NIL) OR (LEN(data.bytes) # data.size) THEN NEW(data.bytes, data.size) END;
  441. IF section.alignment > 0 THEN
  442. INC(data.pos, (-data.pos) MOD section.alignment); (* here we assume that base-alignment is ok *)
  443. END;
  444. address := ADDRESSOF(data.bytes[0])+data.pos; (* to account for potentially empty variable at end of data ... *)
  445. size := section.bits.GetSize();
  446. section.bits.CopyTo(address, size);
  447. INC(data.pos, size DIV 8);
  448. (*
  449. bitPos:= 0;
  450. WHILE size > 0 DO
  451. value := section.bits.GetBits(bitPos,8);
  452. data.bytes[data.pos] := CHR(value);
  453. DEC(size,8); INC(data.pos); INC(bitPos,8);
  454. END;
  455. *)
  456. IF data.firstAddress = 0 THEN data.firstAddress := address END;
  457. RETURN address
  458. END DoAllocate;
  459. PROCEDURE LoadObj*(CONST name, fileName: ARRAY OF CHAR; VAR res: LONGINT; VAR msg: ARRAY OF CHAR): Modules.Module;
  460. TYPE Body=PROCEDURE;
  461. VAR
  462. file: Files.File; reader: Files.Reader; linker: Linker;
  463. arrangement: Arrangement; diagnostics: Diagnostics.StreamDiagnostics; stringWriter: Streams.StringWriter;
  464. module: Modules.Module; heapBlockAdr,moduleAdr: LONGINT;
  465. Log: Streams.Writer;
  466. BEGIN
  467. file := Files.Old(fileName);
  468. IF file # NIL THEN
  469. IF TraceLoading THEN Trace.String("loading"); Trace.String(fileName); Trace.Ln END;
  470. res := Ok; msg[0] := 0X;
  471. Files.OpenReader(reader, file, 0);
  472. NEW(arrangement); NEW(stringWriter,256);
  473. Streams.OpenWriter( Log, KernelLog.Send );
  474. NEW(diagnostics,Log);
  475. NEW(linker, diagnostics, NIL, arrangement, arrangement,name);
  476. IF TraceLoading THEN Trace.String("before linking"); Trace.Ln END;
  477. GenericLinker.Process (reader, linker);
  478. IF ~linker.error THEN linker.Resolve END;
  479. IF ~linker.error THEN linker.Link END;
  480. (*D.Update;*)
  481. IF ~linker.error THEN
  482. IF TraceLoading THEN Trace.String("linking done"); Trace.Ln END;
  483. moduleAdr := linker.moduleBlock.address;
  484. IF ~Machine.IsCooperative THEN
  485. SYSTEM.GET(moduleAdr+3*SIZEOF(ADDRESS), moduleAdr);
  486. SYSTEM.GET(moduleAdr-2*SIZEOF(ADDRESS), heapBlockAdr);
  487. ASSERT(heapBlockAdr = linker.moduleBlock.address+2*SIZEOF(ADDRESS));
  488. END;
  489. module := SYSTEM.VAL(Modules.Module,moduleAdr);
  490. module.staticTypeDescs := testTypeDescs; (* trick to identify new object file loaded modules *)
  491. module.data := arrangement.data.bytes;
  492. module.code := arrangement.code.bytes;
  493. module.sb := 0 (*arrangement.data.firstAddress*); (* zero is correct ! *)
  494. module.body := SYSTEM.VAL(Body, arrangement.bodyAddress);
  495. (*
  496. SortProcTable(module);
  497. SelectionSort(module.exTable);
  498. *)
  499. (*
  500. careful: when GC uses a heuristic for pointer detection on the stack, it will not
  501. trace the module because the module is not reachable as a heap block in a sweep
  502. Therefore the code and data array has to be secured in addition.
  503. Here this is made sure to enter the module in the data structure before returning it.
  504. *)
  505. Modules.Initialize(module);
  506. ELSE module := NIL; res := LinkerError; stringWriter.Update; stringWriter.Get(msg);
  507. END;
  508. ELSE
  509. res := FileNotFound; COPY(fileName, msg); Modules.Append(" not found", msg)
  510. END;
  511. IF res # Ok THEN module := NIL END;
  512. IF (res # Ok) & (res # FileNotFound) THEN D.String(msg);D.Ln END;
  513. RETURN module
  514. FINALLY
  515. res := CommandTrapped;
  516. RETURN NIL
  517. END LoadObj;
  518. PROCEDURE Install*;
  519. VAR extension: ARRAY 32 OF CHAR;
  520. BEGIN
  521. Machine.GetConfig("ObjectFileExtension", extension);
  522. IF extension = "" THEN
  523. COPY(".Gof", extension)
  524. END;
  525. Modules.AddLoader(extension, LoadObj);
  526. END Install;
  527. PROCEDURE Remove*;
  528. BEGIN
  529. Modules.RemoveLoader(".Gof",LoadObj);
  530. END Remove;
  531. BEGIN
  532. NEW(testTypeDescs,1);
  533. Modules.InstallTermHandler(Remove);
  534. StringPool.GetIndex("Oberon",OberonName);
  535. StringPool.GetIndex("@Module",InternalModuleName);
  536. NEW(moduleList);
  537. Install;
  538. END GenericLoader.
  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: LONGINT; 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. *)