FoxIntermediateLinker.Mod 56 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495
  1. MODULE FoxIntermediateLinker;
  2. IMPORT
  3. Strings, Diagnostics, D := Debugging, SyntaxTree := FoxSyntaxTree, Sections := FoxSections,
  4. IntermediateCode := FoxIntermediateCode, Basic := FoxBasic, Streams, Files, Backend := FoxBackend,
  5. Global := FoxGlobal, Formats := FoxFormats,
  6. ObjectFile, BinaryCode := FoxBinaryCode, Commands, Options, IRObjectFile := FoxIntermediateObjectFile,
  7. GenericLinker, StaticLinker;
  8. CONST
  9. DefaultBackend = "AMD";
  10. TYPE
  11. SectionName* = ObjectFile.SectionName; (*ARRAY 256 OF CHAR; (*! move *)*)
  12. (** the assemblinker **)
  13. Linker* = OBJECT
  14. CONST
  15. Trace = FALSE;
  16. RequireSortedSections = FALSE; (* whether the sections in the generated modules are sorted w.r.t. their fixed positions *)
  17. TYPE
  18. ArrangementRestriction = RECORD
  19. fixed: BOOLEAN;
  20. positionOrAlignment: LONGINT;
  21. END;
  22. VAR
  23. backend-: Backend.Backend;
  24. diagnostics: Diagnostics.Diagnostics;
  25. platformName: SyntaxTree.IdentifierString;
  26. importList, loadedModules: Sections.NameList;
  27. allSections: Sections.SectionList;
  28. isSorted, alreadyPrearrangedSinceLastSort: BOOLEAN;
  29. originalRestrictions: POINTER TO ARRAY OF ArrangementRestriction;
  30. objectFile-: IRObjectFile.ObjectFileFormat;
  31. PROCEDURE & Init*(diagnostics: Diagnostics.Diagnostics; defaultBackend: Backend.Backend);
  32. BEGIN
  33. IF diagnostics = NIL THEN
  34. SELF.diagnostics := Basic.GetDefaultDiagnostics()
  35. ELSE
  36. SELF.diagnostics := diagnostics;
  37. END;
  38. backend := defaultBackend;
  39. defaultBackend.GetDescription(platformName);
  40. NEW(allSections);
  41. NEW(importList, 128);
  42. NEW(loadedModules, 128);
  43. NEW(objectFile); objectFile.Initialize(diagnostics);
  44. isSorted := FALSE
  45. END Init;
  46. PROCEDURE PatchStackSize*(CONST typeName: SectionName; size: LONGINT);
  47. VAR sectionName: SectionName; section: Sections.Section; pooledName: Basic.SegmentedName; op1, op2, op3: IntermediateCode.Operand; instruction: IntermediateCode.Instruction;
  48. BEGIN
  49. TRACE(size);
  50. COPY(typeName, sectionName);
  51. Strings.Append(sectionName,".@StackAllocation");
  52. Basic.ToSegmentedName(sectionName, pooledName);
  53. section := allSections.FindByName(pooledName);
  54. instruction := section(IntermediateCode.Section).instructions[0];
  55. op1 := instruction.op1;
  56. op2 := instruction.op2;
  57. op3 := instruction.op3;
  58. IntermediateCode.SetIntValue(op2, size);
  59. section(IntermediateCode.Section).PatchOperands(0, op1, op2, op3);
  60. END PatchStackSize;
  61. PROCEDURE EmitAt(section: IntermediateCode.Section; index: LONGINT; CONST instruction: IntermediateCode.Instruction);
  62. VAR reserve: IntermediateCode.Instruction; op: IntermediateCode.Operand;
  63. BEGIN
  64. IF index = section.pc THEN
  65. section.Emit(instruction)
  66. ELSIF index < section.pc THEN
  67. section.EmitAt(index, instruction)
  68. ELSE
  69. IntermediateCode.InitImmediate(op, instruction.op1.type, 1);
  70. IntermediateCode.InitInstruction1(reserve,Basic.invalidPosition, IntermediateCode.reserve, op);
  71. WHILE (section.pc < index) DO
  72. section.Emit(reserve);
  73. END;
  74. section.Emit(instruction);
  75. END
  76. END EmitAt;
  77. PROCEDURE PatchIntegerValue*(CONST sectionName: ARRAY OF CHAR; index: LONGINT; value: HUGEINT; type: SyntaxTree.Type): BOOLEAN;
  78. VAR instruction: IntermediateCode.Instruction; section: Sections.Section; op1: IntermediateCode.Operand;
  79. pooledName: Basic.SegmentedName; itype: IntermediateCode.Type;
  80. BEGIN
  81. Basic.ToSegmentedName(sectionName, pooledName);
  82. section := allSections.FindByName(pooledName);
  83. IF section = NIL THEN
  84. TRACE(sectionName);
  85. RETURN FALSE
  86. END; (* nothing to patch *)
  87. itype := IntermediateCode.GetType(backend.system, type);
  88. IntermediateCode.InitImmediate(op1,itype, value);
  89. IntermediateCode.InitInstruction1(instruction, Basic.invalidPosition, IntermediateCode.data, op1);
  90. EmitAt(section(IntermediateCode.Section),index, instruction);
  91. RETURN TRUE;
  92. END PatchIntegerValue;
  93. PROCEDURE PatchBooleanValue*(CONST sectionName: ARRAY OF CHAR;index: LONGINT; value: BOOLEAN): BOOLEAN;
  94. VAR instruction: IntermediateCode.Instruction; section: Sections.Section; op1: IntermediateCode.Operand;
  95. pooledName: Basic.SegmentedName; type: IntermediateCode.Type;
  96. BEGIN
  97. Basic.ToSegmentedName(sectionName, pooledName);
  98. section := allSections.FindByName(pooledName);
  99. IF section = NIL THEN RETURN FALSE END; (* nothing to patch *)
  100. type := IntermediateCode.GetType(backend.system, backend.system.booleanType);
  101. IF value THEN
  102. IntermediateCode.InitImmediate(op1, type, 1);
  103. ELSE
  104. IntermediateCode.InitImmediate(op1, type, 0);
  105. END;
  106. IntermediateCode.InitInstruction1(instruction, Basic.invalidPosition, IntermediateCode.data, op1);
  107. EmitAt(section(IntermediateCode.Section), index, instruction);
  108. RETURN TRUE;
  109. END PatchBooleanValue;
  110. PROCEDURE PatchStringValue*(CONST sectionName: ARRAY OF CHAR; CONST value: ARRAY OF CHAR): BOOLEAN;
  111. VAR instruction: IntermediateCode.Instruction; section: Sections.Section; op1: IntermediateCode.Operand;
  112. pooledName: Basic.SegmentedName; type: IntermediateCode.Type;
  113. char: CHAR; i: LONGINT;
  114. BEGIN
  115. Basic.ToSegmentedName(sectionName, pooledName);
  116. section := allSections.FindByName(pooledName);
  117. IF section = NIL THEN RETURN FALSE END; (* nothing to patch *)
  118. section(IntermediateCode.Section).Reset;
  119. type := IntermediateCode.GetType(backend.system, backend.system.characterType);
  120. i := 0;
  121. REPEAT
  122. char := value[i];
  123. IntermediateCode.InitImmediate(op1, type, ORD(char));
  124. IntermediateCode.InitInstruction1(instruction, Basic.invalidPosition, IntermediateCode.data, op1);
  125. section(IntermediateCode.Section).Emit(instruction);
  126. INC(i);
  127. UNTIL char = 0X;
  128. RETURN TRUE;
  129. END PatchStringValue;
  130. PROCEDURE LoadModule*(CONST moduleFileName: ARRAY OF CHAR; recursive: BOOLEAN): BOOLEAN;
  131. VAR
  132. filename, moduleName: SyntaxTree.IdentifierString;
  133. msg: ARRAY 128 OF CHAR;
  134. i: LONGINT;
  135. module: Sections.Module;
  136. name: SyntaxTree.IdentifierString;
  137. BEGIN
  138. FileNameToModuleName(moduleFileName, moduleName);
  139. (* check if the module has already been incorporated *)
  140. IF loadedModules.ContainsName(moduleName) THEN
  141. IF Trace THEN D.String(">>> module "); D.String(moduleName); D.String(" has already been loaded"); D.Ln END;
  142. RETURN TRUE
  143. ELSE
  144. IF (moduleName=Global.StringSystemModule) OR (moduleName=Global.StringsystemModule) THEN
  145. (* nothing to do *)
  146. ELSE
  147. (* open corresponding intermediate code file *)
  148. module := objectFile.Import(moduleName, backend.GetSystem());
  149. IF module = NIL THEN
  150. msg := "failed to import IR file ";
  151. Strings.Append(msg, moduleFileName);
  152. Basic.Error(diagnostics, filename, Basic.invalidPosition, msg);
  153. RETURN FALSE
  154. ELSE
  155. loadedModules.AddName(moduleName); (* to avoid recursive reloading this must be done before parsing *)
  156. IF recursive THEN
  157. FOR i := 0 TO module.imports.Length()-1 DO
  158. name := module.imports.GetName(i);
  159. IF ~LoadModule(name, recursive) THEN
  160. msg := "failed to import ";
  161. Strings.Append(msg, name);
  162. Basic.Error(diagnostics, filename, Basic.invalidPosition, msg);
  163. RETURN FALSE
  164. END;
  165. END;
  166. END;
  167. CopySections(module.allSections, allSections);
  168. IF Trace THEN
  169. D.String(">>> IR file successfully parsed: "); D.String(filename); D.Ln;
  170. DumpSections(D.Log, allSections);
  171. END;
  172. isSorted := FALSE; (* sections are not sorted anymore *)
  173. RETURN TRUE
  174. END
  175. END;
  176. RETURN TRUE
  177. END
  178. END LoadModule;
  179. PROCEDURE LinkPrefixed*(CONST sectionPrefix: ARRAY OF CHAR): BOOLEAN;
  180. VAR segmentedName: Basic.SegmentedName; filename: Files.FileName;
  181. BEGIN
  182. SectionNameToFileName(sectionPrefix, filename);
  183. MarkReachabilityOfAll(FALSE);
  184. IF LoadModule(filename, TRUE) THEN
  185. segmentedName := sectionPrefix;
  186. MarkAsReachableStartingWith(segmentedName, {Sections.InitCodeSection, Sections.BodyCodeSection});
  187. RETURN TRUE;
  188. ELSE
  189. RETURN FALSE;
  190. END;
  191. END LinkPrefixed;
  192. (** mark a section with a certain name as reachable **)
  193. PROCEDURE MarkAsReachableByName*(CONST name: ARRAY OF CHAR);
  194. VAR
  195. section: Sections.Section;
  196. pooledName: Basic.SegmentedName;
  197. BEGIN
  198. Basic.ToSegmentedName(name, pooledName);
  199. section:= allSections.FindByName(pooledName);
  200. ASSERT(section # NIL);
  201. MarkAsReachable(section)
  202. END MarkAsReachableByName;
  203. (** mark all sections whose names start with a certain prefix as reachable **)
  204. PROCEDURE MarkAsReachableStartingWith*(CONST prefix: Basic.SegmentedName; allowedSections: SET);
  205. VAR
  206. section: Sections.Section; name: Basic.SegmentedName;
  207. i: LONGINT;
  208. BEGIN
  209. (* TODO: could or should one make this faster using a hash table? *)
  210. (* go through all sections *)
  211. FOR i := 0 TO allSections.Length() - 1 DO
  212. section := allSections.GetSection(i);
  213. IF section.type IN allowedSections THEN
  214. IF Basic.IsPrefix(prefix, section.name) THEN
  215. name := section.name;
  216. Basic.RemoveSuffix(name);
  217. IF prefix = name THEN
  218. MarkAsReachable(section)
  219. END
  220. END
  221. END;
  222. END
  223. END MarkAsReachableStartingWith;
  224. (*
  225. PROCEDURE ModuleIsReachable(CONST name: Basic.String): BOOLEAN;
  226. VAR i: LONGINT; section: Sections.Section;
  227. BEGIN
  228. FOR i := 0 TO allSections.Length()-1 DO
  229. section := allSections.GetSection(i);
  230. IF (section.name[0] = name) & section.isReachable THEN
  231. RETURN TRUE
  232. END;
  233. END;
  234. RETURN FALSE
  235. END ModuleIsReachable;
  236. *)
  237. PROCEDURE OperandSection(CONST operand: IntermediateCode.Operand): Sections.Section;
  238. VAR section: Sections.Section;
  239. BEGIN
  240. section := allSections.FindByName(operand.symbol.name);
  241. IF section = NIL THEN D.String("not found section: "); Basic.WriteSegmentedName(D.Log, operand.symbol.name); D.Ln END;
  242. RETURN allSections.FindByName(operand.symbol.name);
  243. END OperandSection;
  244. (** mark a section as reachable and do the same recursively for all referenced sections **)
  245. PROCEDURE MarkAsReachable*(section: Sections.Section);
  246. VAR
  247. intermediateCodeSection: IntermediateCode.Section;
  248. i: LONGINT;
  249. procedureName, moduleName: SyntaxTree.IdentifierString;
  250. prefix: Basic.SegmentedName;
  251. BEGIN
  252. IF ~section.isReachable THEN
  253. IF Trace THEN D.String(">>> MarkAsReachable "); Basic.WriteSegmentedName(D.Log, section.name); D.Ln END;
  254. section.SetReachability(TRUE);
  255. prefix := section.name; Basic.RemoveSuffix(prefix);
  256. MarkAsReachableStartingWith(prefix, {Sections.InitCodeSection});
  257. ASSERT(section IS IntermediateCode.Section);
  258. intermediateCodeSection := section(IntermediateCode.Section);
  259. (* go through all instructions in the section *)
  260. FOR i := 0 TO intermediateCodeSection.pc - 1 DO
  261. IF ~backend(IntermediateCode.IntermediateBackend).SupportedInstruction(intermediateCodeSection.instructions[i], moduleName, procedureName) THEN
  262. Strings.Append(moduleName,".");
  263. Strings.Append(moduleName, procedureName);
  264. MarkAsReachableByName(moduleName);
  265. END;
  266. IF intermediateCodeSection.instructions[i].op1.symbol.name # "" THEN MarkAsReachable(OperandSection(intermediateCodeSection.instructions[i].op1)) END;
  267. IF intermediateCodeSection.instructions[i].op2.symbol.name # "" THEN MarkAsReachable(OperandSection(intermediateCodeSection.instructions[i].op2)) END;
  268. IF intermediateCodeSection.instructions[i].op3.symbol.name # "" THEN MarkAsReachable(OperandSection(intermediateCodeSection.instructions[i].op3)) END
  269. END
  270. END
  271. END MarkAsReachable;
  272. (** mark all sections as either reachable or unreachable **)
  273. PROCEDURE MarkReachabilityOfAll*(isReachable: BOOLEAN);
  274. VAR
  275. section: Sections.Section;
  276. i: LONGINT;
  277. BEGIN
  278. IF Trace THEN D.String(">>> MarkReachabilityOfAll "); IF isReachable THEN D.String("TRUE") ELSE D.String("FALSE") END; D.Ln END;
  279. FOR i := 0 TO allSections.Length() - 1 DO
  280. section := allSections.GetSection(i);
  281. section.SetReachability(isReachable)
  282. END
  283. END MarkReachabilityOfAll;
  284. (** dump all sections (both reachable and not) **)
  285. PROCEDURE DumpSections*(writer: Streams.Writer; sections: Sections.SectionList);
  286. VAR
  287. section: Sections.Section;
  288. i: LONGINT;
  289. BEGIN
  290. FOR i := 0 TO sections.Length() - 1 DO
  291. section := sections.GetSection(i);
  292. IF section.isReachable THEN
  293. writer.String("REACHABLE ")
  294. ELSE
  295. writer.String("unreachable ")
  296. END;
  297. section.Dump(writer)
  298. END;
  299. writer.Update
  300. END DumpSections;
  301. (** store the original arrangment restrictions of all sections **)
  302. PROCEDURE StoreOriginalRestrictions;
  303. VAR
  304. section: Sections.Section;
  305. i: LONGINT;
  306. BEGIN
  307. NEW(originalRestrictions, allSections.Length());
  308. FOR i := 0 TO allSections.Length() - 1 DO
  309. section := allSections.GetSection(i);
  310. originalRestrictions[i].fixed := section.fixed;
  311. originalRestrictions[i].positionOrAlignment := section.positionOrAlignment
  312. END
  313. END StoreOriginalRestrictions;
  314. (** restore the original arrangment restrictions of all sections **)
  315. PROCEDURE RestoreOriginalRestrictions;
  316. VAR
  317. section: Sections.Section;
  318. i: LONGINT;
  319. BEGIN
  320. ASSERT(LEN(originalRestrictions) = allSections.Length());
  321. FOR i := 0 TO allSections.Length() - 1 DO
  322. section := allSections.GetSection(i);
  323. section.SetPositionOrAlignment(originalRestrictions[i].fixed, originalRestrictions[i].positionOrAlignment)
  324. END
  325. END RestoreOriginalRestrictions;
  326. PROCEDURE PrearrangeReachableDataSections*;
  327. VAR
  328. fixedDataSections, flexibleDataSections: Sections.SectionList;
  329. section, fixedDataSection, flexibleDataSection: Sections.Section;
  330. i, currentAddress, nextOccupiedAddress, flexibleDataSectionIndex, fixedDataSectionIndex, startAddress, endAddress: LONGINT;
  331. done: BOOLEAN;
  332. BEGIN
  333. (* sort sections if necessary *)
  334. IF ~isSorted THEN
  335. IF Trace THEN D.String("++++++++++ before sorting ++++++++++"); DumpSections(D.Log, allSections) END;
  336. FOR i:= 0 TO allSections.Length() - 1 DO
  337. allSections.GetSection(i).SetOffset(i)
  338. END;
  339. allSections.Sort(SectionPositionAndSizeComparison);
  340. IF Trace THEN D.String("++++++++++ after sorting ++++++++++"); DumpSections(D.Log, allSections) END;
  341. isSorted := TRUE;
  342. alreadyPrearrangedSinceLastSort := FALSE
  343. END;
  344. ASSERT(isSorted);
  345. IF alreadyPrearrangedSinceLastSort THEN RestoreOriginalRestrictions ELSE StoreOriginalRestrictions END;
  346. IF Trace THEN D.String("before prearrangement"); D.Ln; DumpSections(D.Log, allSections); D.Ln END;
  347. (* create new lists for reachable data sections that are fixed or flexible, respectively *)
  348. NEW(fixedDataSections);
  349. NEW(flexibleDataSections);
  350. (* go through all reachable data sections, and put them into one of two lists *)
  351. FOR i:= 0 TO allSections.Length() - 1 DO
  352. section := allSections.GetSection(i);
  353. IF section.isReachable & ((section.type = Sections.ConstSection) OR (section.type = Sections.VarSection)) THEN
  354. IF section.fixed THEN
  355. fixedDataSections.AddSection(section)
  356. ELSE
  357. flexibleDataSections.AddSection(section)
  358. END
  359. END
  360. END;
  361. IF Trace THEN
  362. D.String("++++++++++ reachable fixed data sections ++++++++++"); fixedDataSections.Dump(D.Log); D.Ln;
  363. D.String("++++++++++ reachable flexible data sections ++++++++++"); flexibleDataSections.Dump(D.Log); D.Ln;
  364. END;
  365. (* arrange the sections (i.e. set the fixed attribute) such that the given fixed-positions and alignments are respected *)
  366. currentAddress := 0;
  367. flexibleDataSectionIndex := 0;
  368. (* go through all fixed data sections of the cell *)
  369. FOR fixedDataSectionIndex := 0 TO fixedDataSections.Length() DO (* note: the index may be out-of-bounds! *)
  370. IF fixedDataSectionIndex < fixedDataSections.Length() THEN
  371. fixedDataSection := fixedDataSections.GetSection(fixedDataSectionIndex);
  372. ASSERT(fixedDataSection.fixed);
  373. nextOccupiedAddress := fixedDataSection.positionOrAlignment
  374. ELSE
  375. (* there is no more fixed data section *)
  376. nextOccupiedAddress := MAX(LONGINT)
  377. END;
  378. done := FALSE;
  379. WHILE ~done DO
  380. IF flexibleDataSectionIndex < flexibleDataSections.Length() THEN
  381. flexibleDataSection := flexibleDataSections.GetSection(flexibleDataSectionIndex);
  382. (* determine start-address of the next section (respect alignment) *)
  383. IF flexibleDataSection.IsAligned() & ((currentAddress MOD flexibleDataSection.positionOrAlignment) # 0) THEN
  384. startAddress := currentAddress + flexibleDataSection.positionOrAlignment - (currentAddress MOD flexibleDataSection.positionOrAlignment)
  385. ELSE
  386. startAddress := currentAddress
  387. END;
  388. (* determine end-address fo the next section *)
  389. endAddress := startAddress + flexibleDataSection.GetSize();
  390. IF endAddress <= nextOccupiedAddress THEN
  391. (* there is enough space for the section *)
  392. flexibleDataSection.SetPositionOrAlignment(TRUE, startAddress); (* position is set for section *)
  393. INC(flexibleDataSectionIndex);
  394. currentAddress := endAddress
  395. ELSE
  396. (* there is no more space for sections *)
  397. done := TRUE
  398. END
  399. ELSE
  400. (* there are no more flexible data sections *)
  401. done := TRUE
  402. END
  403. END;
  404. IF fixedDataSectionIndex < fixedDataSections.Length() THEN
  405. ASSERT(fixedDataSection.GetSize() # Sections.UnknownSize);
  406. currentAddress := fixedDataSection.positionOrAlignment + fixedDataSection.GetSize()
  407. END
  408. END;
  409. alreadyPrearrangedSinceLastSort := TRUE;
  410. IF Trace THEN D.String("after prearrangement"); D.Ln; DumpSections(D.Log, allSections); D.Ln END;
  411. END PrearrangeReachableDataSections;
  412. PROCEDURE PatchValueInSection*(CONST sectionName: Basic.SegmentedName; syntaxTreeValue: SyntaxTree.Value);
  413. VAR
  414. section: Sections.Section;
  415. emptyOperand, dataOperand: IntermediateCode.Operand;
  416. dataInstruction: IntermediateCode.Instruction;
  417. hugeintValue: HUGEINT;
  418. BEGIN
  419. section := allSections.FindByName(sectionName);
  420. ASSERT(section # NIL);
  421. IF syntaxTreeValue IS SyntaxTree.BooleanValue THEN
  422. (* BOOLEAN *)
  423. IF syntaxTreeValue(SyntaxTree.BooleanValue).value THEN hugeintValue := 1 ELSE hugeintValue := 0 END
  424. ELSIF syntaxTreeValue IS SyntaxTree.IntegerValue THEN
  425. (* INTEGER *)
  426. hugeintValue := syntaxTreeValue(SyntaxTree.IntegerValue).hvalue;
  427. ELSE
  428. HALT(100)
  429. END;
  430. IntermediateCode.InitImmediate(dataOperand, IntermediateCode.GetType(backend.GetSystem(), syntaxTreeValue.type.resolved), hugeintValue);
  431. IntermediateCode.InitOperand(emptyOperand);
  432. IntermediateCode.InitInstruction(dataInstruction, Basic.invalidPosition, IntermediateCode.data, dataOperand, emptyOperand, emptyOperand);
  433. ASSERT(section IS IntermediateCode.Section);
  434. section(IntermediateCode.Section).EmitAt(0, dataInstruction)
  435. END PatchValueInSection;
  436. (** get all reachable sections in the form of an intermediate code module with a certain name **)
  437. PROCEDURE ExtractModuleWithName(CONST desiredName: ARRAY OF CHAR): Sections.Module;
  438. VAR
  439. result: Sections.Module;
  440. section: Sections.Section;
  441. i: LONGINT;
  442. BEGIN
  443. NEW(result, NIL, backend.GetSystem()); (* note: there is no syntax tree *)
  444. result.SetModuleName(desiredName);
  445. result.SetPlatformName(platformName);
  446. result.SetImports(importList);
  447. (* add all of the reachable sections from the cumulative section list into the resulting module's section list *)
  448. FOR i := 0 TO allSections.Length() - 1 DO
  449. section := allSections.GetSection(i);
  450. (* remove any previously generated code *)
  451. ASSERT(section IS IntermediateCode.Section);
  452. section(IntermediateCode.Section).SetResolved(NIL);
  453. IF section.isReachable THEN result.allSections.AddSection(section) END
  454. END;
  455. IF RequireSortedSections THEN result.allSections.Sort(SectionPositionComparison) END;
  456. IF Trace THEN D.String("+++++++++ intermediate code module ++++++++++"); D.Ln; result.Dump(D.Log); D.Ln; END;
  457. RETURN result
  458. END ExtractModuleWithName;
  459. PROCEDURE SectionPositionComparison(leftObject, rightObject: ANY): BOOLEAN;
  460. VAR
  461. leftSection, rightSection: Sections.Section;
  462. leftPosition, rightPosition: LONGINT;
  463. BEGIN
  464. ASSERT((leftObject IS Sections.Section) & (rightObject IS Sections.Section));
  465. leftSection := leftObject(Sections.Section);
  466. rightSection := rightObject(Sections.Section);
  467. IF leftSection.fixed THEN
  468. leftPosition := leftSection.positionOrAlignment
  469. ELSE
  470. leftPosition := MAX(LONGINT)
  471. END;
  472. IF rightSection.fixed THEN
  473. rightPosition := rightSection.positionOrAlignment
  474. ELSE
  475. rightPosition := MAX(LONGINT)
  476. END;
  477. IF leftSection.IsCode() & rightSection.IsCode() THEN RETURN FALSE END;
  478. RETURN leftPosition < rightPosition
  479. END SectionPositionComparison;
  480. (** whether a section should appear before another one in an assembly (used for sorting)
  481. - 1st priority: when sections have fixed positions, the ones with smaller addresses come first
  482. - 2nd priority: smaller sections come first
  483. **)
  484. PROCEDURE SectionPositionAndSizeComparison(leftObject, rightObject: ANY): BOOLEAN;
  485. VAR
  486. leftSection, rightSection: Sections.Section;
  487. leftPosition, rightPosition, leftSize, rightSize: LONGINT;
  488. BEGIN
  489. ASSERT((leftObject IS Sections.Section) & (rightObject IS Sections.Section));
  490. leftSection := leftObject(Sections.Section);
  491. rightSection := rightObject(Sections.Section);
  492. IF leftSection.fixed THEN
  493. leftPosition := leftSection.positionOrAlignment
  494. ELSE
  495. leftPosition := MAX(LONGINT)
  496. END;
  497. IF rightSection.fixed THEN
  498. rightPosition := rightSection.positionOrAlignment
  499. ELSE
  500. rightPosition := MAX(LONGINT)
  501. END;
  502. IF ~leftSection.IsCode() & rightSection.IsCode() THEN (* data sections first *)
  503. RETURN TRUE
  504. ELSIF leftSection.IsCode() & ~rightSection.IsCode() THEN (* data sections first *)
  505. RETURN FALSE
  506. ELSIF leftSection.IsCode() & rightSection.IsCode() THEN (* code sections: sorted by linking preference, stable w.r.t. loading order *)
  507. IF GetPriority(leftSection) < GetPriority(rightSection) THEN
  508. RETURN TRUE
  509. ELSIF GetPriority(leftSection) = GetPriority(rightSection) THEN
  510. RETURN (leftSection.priority < rightSection.priority) OR (leftSection.priority = rightSection.priority) & (leftSection.offset < rightSection.offset) (* must keep order as provided by loader *)
  511. ELSE
  512. RETURN FALSE
  513. END
  514. ELSIF leftPosition < rightPosition THEN (* data sections sorted by position *)
  515. RETURN TRUE
  516. ELSIF leftPosition > rightPosition THEN (* data sections sorted by position *)
  517. RETURN FALSE
  518. ELSE (* data section sorted by size, if no position provided *)
  519. ASSERT(leftPosition = rightPosition); (* note: this is the case for sections without fixed positions *)
  520. leftSize := leftSection.GetSize();
  521. rightSize := rightSection.GetSize();
  522. IF (leftSize = Sections.UnknownSize) OR (leftSize = 0) THEN leftSize := MAX(LONGINT) END;
  523. IF (rightSize = Sections.UnknownSize) OR (rightSize = 0) THEN rightSize := MAX(LONGINT) END;
  524. IF leftSize = rightSize THEN
  525. RETURN leftSection.offset < rightSection.offset (* keeping order as provided by loader, cosmetic *)
  526. ELSE
  527. RETURN leftSize < rightSize
  528. END
  529. END
  530. END SectionPositionAndSizeComparison;
  531. (* set address of sections to a fixed position after compilation *)
  532. PROCEDURE FixSections(binaryModule: Sections.Module; VAR sizes: ARRAY OF LONGINT);
  533. VAR adr,i: LONGINT; section: Sections.Section; is: BinaryCode.Section;
  534. BEGIN
  535. adr := 0;
  536. FOR i := 0 TO binaryModule.allSections.Length()-1 DO
  537. section := binaryModule.allSections.GetSection(i);
  538. is := section(IntermediateCode.Section).resolved;
  539. IF (is # NIL) & section.IsCode() THEN
  540. (*
  541. Basic.WriteSegmentedName(D.Log,section.name);
  542. D.String(" @ "); D.Int(adr,1); D.Ln;
  543. *)
  544. backend.CheckCodeAddress(adr);
  545. is.SetAlignment(TRUE, adr);
  546. IF is.pc > sizes[i] THEN sizes[i] := is.pc END;
  547. adr := adr + sizes[i];
  548. END;
  549. is.Reset; (* enable recompilation *)
  550. END;
  551. END FixSections;
  552. (* check if any of the addresses of sections have changed during last compilation *)
  553. PROCEDURE Conflict(binaryModule: Sections.Module; VAR sizes: ARRAY OF LONGINT): BOOLEAN;
  554. VAR adr,i: LONGINT; section: Sections.Section;is: BinaryCode.Section;
  555. BEGIN
  556. adr := 0;
  557. FOR i := 0 TO binaryModule.allSections.Length()-1 DO
  558. section := binaryModule.allSections.GetSection(i);
  559. is := section(IntermediateCode.Section).resolved;
  560. IF (is # NIL) & section.IsCode() THEN
  561. IF is.pc > sizes[i] THEN RETURN TRUE
  562. (*
  563. not necessary, the linker places correctly.
  564. ELSIF is.pc < sizes[i] THEN is.SetPC(sizes[i]) (* set section size to maximal observed size *)
  565. *)
  566. END;
  567. END;
  568. END;
  569. RETURN FALSE
  570. END Conflict;
  571. (* generate binary code and write an object file with a desired module name *)
  572. PROCEDURE GenerateObjectFile*(objectFileFormat: Formats.ObjectFileFormat; log: Streams.Writer; CONST desiredName: ARRAY OF CHAR): BOOLEAN;
  573. VAR
  574. count: LONGINT;
  575. intermediateCodeModule: Sections.Module;
  576. binaryModule: Formats.GeneratedModule;
  577. result: BOOLEAN;
  578. sizes: POINTER TO ARRAY OF LONGINT; i: LONGINT;
  579. objectFileExtension: ARRAY 32 OF CHAR; objectFileName: Files.FileName;
  580. BEGIN
  581. intermediateCodeModule := ExtractModuleWithName(desiredName);
  582. result := TRUE;
  583. (* generate binary code *)
  584. backend.Initialize(diagnostics, log, {}, NIL, backend.GetSystem());
  585. binaryModule := backend.ProcessIntermediateCodeModule(intermediateCodeModule); count := 0;
  586. (* iterative compilation until all sections remain fixed at their position *)
  587. NEW(sizes, binaryModule(Sections.Module).allSections.Length());
  588. FOR i := 0 TO LEN(sizes)-1 DO sizes[i] := 0 END;
  589. REPEAT
  590. INC(count);
  591. (* fix all section addresses *)
  592. FixSections(binaryModule(Sections.Module),sizes^);
  593. (* compile *)
  594. binaryModule := backend.ProcessIntermediateCodeModule(intermediateCodeModule);
  595. (* and repeat if any of the section addresses have to be adapted *)
  596. UNTIL ~Conflict(binaryModule(Sections.Module),sizes^) OR (count > 10) ;
  597. ASSERT(count <=10);
  598. IF binaryModule = NIL THEN
  599. Basic.Error(diagnostics, desiredName,Basic.invalidPosition, "the specified backend cannot process intermediate code");
  600. result := FALSE
  601. ELSIF backend.error THEN
  602. Basic.Error(diagnostics, desiredName, Basic.invalidPosition, "binary code could not be generated (backend error)");
  603. result := FALSE
  604. ELSE
  605. IF Trace THEN D.String(">>> binary code successfully generated"); D.Ln END;
  606. IF objectFileFormat = NIL THEN
  607. Basic.Error(diagnostics, desiredName, Basic.invalidPosition, "no object file format specified");
  608. result := FALSE
  609. ELSE
  610. (* write the generated code into an object file *)
  611. objectFileFormat.Initialize(diagnostics);
  612. IF objectFileFormat.Export(binaryModule, NIL) THEN
  613. IF log # NIL THEN
  614. log.String("assembled "); log.String(desiredName); log.String(" => ");
  615. objectFileFormat.GetExtension(objectFileExtension);
  616. Files.JoinExtension(desiredName, objectFileExtension, objectFileName);
  617. log.String(objectFileName); log.Ln;
  618. END;
  619. IF Trace THEN D.String(">>> object file successfully written"); D.Ln END;
  620. ELSE
  621. Basic.Error(diagnostics, desiredName, Basic.invalidPosition, "object file could not be written");
  622. result := FALSE
  623. END
  624. END
  625. END;
  626. RETURN result
  627. END GenerateObjectFile;
  628. END Linker;
  629. TYPE
  630. (*
  631. CellLinker = OBJECT
  632. VAR
  633. backend: Backend.Backend;
  634. irLinker: Linker;
  635. outputFormat: Formats.ObjectFileFormat;
  636. system: Global.System;
  637. diagnostics: Diagnostics.Diagnostics;
  638. error: BOOLEAN;
  639. typeName: SectionName;
  640. PROCEDURE &Init(b: Backend.Backend; output: Formats.ObjectFileFormat; CONST inExtension: ARRAY OF CHAR; d: Diagnostics.Diagnostics);
  641. BEGIN
  642. error := FALSE;
  643. SELF.backend := b;
  644. SELF.diagnostics := d;
  645. IF diagnostics = NIL THEN diagnostics := Basic.GetDefaultDiagnostics() END;
  646. SELF.outputFormat := output;
  647. NEW(irLinker, diagnostics, backend, ""); (* TODO: pass an optional path as third parameter *)
  648. IF (inExtension # "") THEN irLinker.objectFile.SetExtension(inExtension) END;
  649. IF ~irLinker.LoadModule(backend(IntermediateCode.IntermediateBackend).runtimeModuleName, TRUE) THEN
  650. error := TRUE;
  651. Basic.Error(diagnostics, backend(IntermediateCode.IntermediateBackend).runtimeModuleName,Diagnostics.Invalid, Diagnostics.Invalid, "could not load ir file");
  652. END;
  653. backend := irLinker.backend;
  654. system := backend.system;
  655. END Init;
  656. PROCEDURE SetInstance*(CONST type: ARRAY OF CHAR): BOOLEAN;
  657. VAR segmentedName: Basic.SegmentedName; filename: Files.FileName;
  658. BEGIN
  659. COPY(type, typeName);
  660. SectionNameToFileName(type, filename);
  661. irLinker.MarkReachabilityOfAll(FALSE);
  662. IF irLinker.LoadModule(filename, TRUE) THEN
  663. segmentedName := type;
  664. irLinker.MarkAsReachableStartingWith(segmentedName, {Sections.InitCodeSection, Sections.BodyCodeSection});
  665. RETURN TRUE;
  666. ELSE
  667. RETURN FALSE;
  668. END;
  669. END SetInstance;
  670. PROCEDURE Generate(CONST instanceName: ARRAY OF CHAR): BOOLEAN;
  671. BEGIN
  672. irLinker.PrearrangeReachableDataSections;
  673. IF irLinker.GenerateObjectFile(outputFormat, NIL, instanceName) THEN
  674. Basic.Information(diagnostics, instanceName, Diagnostics.Invalid, Diagnostics.Invalid, "generated.");
  675. RETURN TRUE
  676. ELSE
  677. RETURN FALSE
  678. END;
  679. END Generate;
  680. (*PROCEDURE LinkInstance(CONST typeName, instanceName: ARRAY OF CHAR): BOOLEAN;
  681. VAR
  682. codeFileName, dataFileName: Files.FileName;
  683. typeName, instanceName, linkRoot: SectionName;
  684. code, data: StaticLinker.Arrangement; linker: GenericLinker.Linker;
  685. i: LONGINT;
  686. logFile: Files.File; linkerLog: Files.Writer;
  687. type: ActiveCells.Type;
  688. msg: MessageString;
  689. objectFileExtension: ARRAY 32 OF CHAR;
  690. instructionMemorySize, dataMemorySize: LONGINT;
  691. parameter: ActiveCells.Parameter;
  692. value: SyntaxTree.Value;
  693. pooledName: Basic.SegmentedName;
  694. device: ActiveCells.Device;
  695. error : BOOLEAN;
  696. CONST MinimalStackSize=64;
  697. BEGIN
  698. error := FALSE;
  699. type := instance.instanceType;
  700. type.GetFullName(typeName,NIL);
  701. instance.GetFullName(instanceName,NIL);
  702. IF TraceLinking THEN
  703. D.String("assembling instance "); D.String(instanceName); D.String(" of type "); D.String(typeName); D.Ln;
  704. END;
  705. IF instance.IsEngine() THEN
  706. IF TraceLinking THEN
  707. D.String("instance "); D.String(instanceName); D.String(" is engine "); D.Ln;
  708. END;
  709. RETURN TRUE;
  710. END;
  711. backend.SetCapabilities(instance.capabilities);
  712. irLinker.MarkReachabilityOfAll(FALSE);
  713. COPY(typeName, linkRoot);
  714. Strings.Append(linkRoot,".@BodyStub");
  715. irLinker.MarkAsReachableByName(linkRoot);
  716. irLinker.PatchStackSize(typeName, instance.dataMemorySize);
  717. FOR i := 0 TO instance.parameters.Length()-1 DO
  718. parameter := instance.parameters.GetParameter(i);
  719. IF parameter.parameterType = 0 THEN (* Boolean *)
  720. value := SyntaxTree.NewBooleanValue(-1, parameter.boolean); value.SetType(system.booleanType);
  721. ELSE
  722. value := SyntaxTree.NewIntegerValue(-1, parameter.integer); value.SetType(system.integerType);
  723. END;
  724. Basic.ToSegmentedName(parameter.name, pooledName);
  725. irLinker.PatchValueInSection(pooledName,value);
  726. END;
  727. FOR i := 0 TO type.specification.supportedDevices.Length()-1 DO
  728. device := type.specification.supportedDevices.GetDevice(i);
  729. IF instance.instanceType.devices.ByName(device.name) = NIL THEN
  730. IF irLinker.ModuleIsReachable(Basic.MakeString(device.name)) THEN
  731. msg := "Missing device capability ";
  732. Strings.Append(msg, device.name);
  733. Strings.Append(msg," in cell ");
  734. instance.AppendToMsg(msg);
  735. Basic.Error(diagnostics, specification.name,Diagnostics.Invalid, Diagnostics.Invalid, msg);
  736. error := TRUE;
  737. END;
  738. ELSE
  739. IF ~irLinker.ModuleIsReachable(Basic.MakeString(device.name)) THEN
  740. msg := "Unused device ";
  741. Strings.Append(msg, device.name);
  742. Strings.Append(msg," in cell ");
  743. instance.AppendToMsg(msg);
  744. Basic.Warning(diagnostics, specification.name,Diagnostics.Invalid,Diagnostics.Invalid,msg);
  745. END;
  746. END;
  747. END;
  748. IF error THEN RETURN FALSE END;
  749. objectFileFormat.GetExtension(objectFileExtension);
  750. irLinker.PrearrangeReachableDataSections;
  751. IF ~irLinker.GenerateObjectFile(objectFileFormat, specification.log, instanceName) THEN
  752. Basic.Error(diagnostics, specification.name,Diagnostics.Invalid, Diagnostics.Invalid, "could not generate object file");
  753. RETURN FALSE
  754. END;
  755. IF TraceLinking THEN
  756. D.String("assembling instance done. "); D.Ln;
  757. END;
  758. NEW (code, 0); NEW (data, 0);
  759. COPY(instanceName, msg); Strings.Append(msg,".log"); logFile := Files.New(msg);
  760. IF logFile # NIL THEN NEW(linkerLog,logFile,0) ELSE logFile := NIL END;
  761. NEW (linker, specification.diagnostics, linkerLog, GenericLinker.UseInitCode, code, data);
  762. linker.SetLinkRoot("" (* linkRoot *)); (* take all initcode sections *)
  763. StaticLinker.ReadObjectFile(instanceName, "",objectFileExtension,linker);
  764. (* do linking after having read in all blocks to account for potential constraints *)
  765. IF ~linker.error THEN linker.Link; END;
  766. system := backend.GetSystem();
  767. instructionMemorySize := instance.instructionMemorySize;
  768. dataMemorySize := instance.dataMemorySize;
  769. IF instructionMemorySize = 0 THEN
  770. instructionMemorySize := type.instructionMemorySize
  771. END;
  772. IF dataMemorySize = 0 THEN
  773. dataMemorySize := type.dataMemorySize
  774. END;
  775. IF (instructionMemorySize > 0) & (instructionMemorySize < code.SizeInBits() DIV system.codeUnit) THEN
  776. Basic.Error(diagnostics, instanceName,Diagnostics.Invalid, Diagnostics.Invalid, "specified instruction memory size too small");
  777. error := TRUE;
  778. ELSIF instructionMemorySize = 0 THEN
  779. instructionMemorySize := code.SizeInBits() DIV system.codeUnit;
  780. END;
  781. dataMemorySize := MAX(data.SizeInBits() DIV system.dataUnit, dataMemorySize);
  782. instance.SetInstructionMemorySize(instructionMemorySize);
  783. instance.SetDataMemorySize(dataMemorySize);
  784. IF (dataMemorySize - data.SizeInBits() DIV system.dataUnit) < MinimalStackSize THEN
  785. Basic.Error(diagnostics, specification.name,Diagnostics.Invalid, Diagnostics.Invalid, "specified data memory size too small");
  786. error := TRUE;
  787. END;
  788. Files.JoinExtension(instanceName,ActiveCells.CodeFileExtension,codeFileName);
  789. Files.JoinExtension(instanceName,ActiveCells.DataFileExtension,dataFileName);
  790. IF ~linker.error THEN
  791. StaticLinker.WriteOutputFile (code, codeFileName, linker, StaticLinker.WriteTRMCodeFile);
  792. StaticLinker.WriteOutputFile (data, dataFileName, linker, StaticLinker.WriteTRMDataFile);
  793. IF linkerLog # NIL THEN linkerLog.Update; Files.Register(logFile) END;
  794. IF specification.log # NIL THEN
  795. specification.log.String(instanceName);
  796. specification.log.String(" linked. IM = ");specification.log.Int(instructionMemorySize,1);
  797. specification.log.String(" (used: "); specification.log.Int(code.SizeInBits() DIV system.codeUnit,1);
  798. specification.log.String("), DM = "); specification.log.Int(dataMemorySize,1);
  799. specification.log.String(" (used: "); specification.log.Int(data.SizeInBits() DIV system.dataUnit,1);
  800. specification.log.String(")");
  801. specification.log.Ln; specification.log.Update;
  802. specification.log.String("generated code file: ");specification.log.String(codeFileName); specification.log.Ln;
  803. specification.log.String("generated data file: ");specification.log.String(dataFileName); specification.log.Ln;
  804. END;
  805. ELSE
  806. msg := "could not link ";
  807. Strings.Append(msg,linkRoot);
  808. Basic.Error(diagnostics, "",Diagnostics.Invalid, Diagnostics.Invalid, msg);
  809. END;
  810. RETURN ~linker.error & ~error
  811. END LinkInstance;
  812. *)
  813. END CellLinker;
  814. *)
  815. (*
  816. SpecificationLinker=OBJECT (Backend.Backend)
  817. VAR objectFileFormat: Formats.ObjectFileFormat;
  818. PROCEDURE &Init;
  819. BEGIN
  820. InitBackend;
  821. objectFileFormat := Formats.GetObjectFileFormat("Generic");
  822. END Init;
  823. PROCEDURE Emit(backend: Backend.Backend): BOOLEAN;
  824. BEGIN
  825. RETURN LinkActiveCells(activeCellsSpecification, backend, objectFileFormat);
  826. END Emit;
  827. PROCEDURE DefineOptions(options: Options.Options);
  828. BEGIN
  829. objectFileFormat.DefineOptions(options);
  830. END DefineOptions;
  831. PROCEDURE GetOptions(options: Options.Options);
  832. BEGIN
  833. objectFileFormat.GetOptions(options);
  834. END GetOptions;
  835. END SpecificationLinker;
  836. PROCEDURE Get*(): Backend.Backend;
  837. VAR backend: SpecificationLinker;
  838. BEGIN
  839. NEW(backend); RETURN backend
  840. END Get;
  841. *)
  842. PROCEDURE FileNameToModuleName(CONST filename: ARRAY OF CHAR; VAR moduleName: ARRAY OF CHAR);
  843. VAR extension: Files.FileName;
  844. BEGIN
  845. Files.SplitExtension(filename, moduleName, extension);
  846. END FileNameToModuleName;
  847. PROCEDURE SectionNameToFileName(CONST sectionName: ARRAY OF CHAR; VAR fileName: ARRAY OF CHAR);
  848. VAR i: LONGINT;
  849. BEGIN
  850. i := 0;
  851. WHILE (sectionName[i] # 0X) & (sectionName[i] # ".") DO
  852. fileName[i] := sectionName[i];
  853. INC(i);
  854. END;
  855. fileName[i] := 0X;
  856. END SectionNameToFileName;
  857. PROCEDURE GetPriority*(block: Sections.Section): LONGINT;
  858. CONST Fixed=0; InitCode=1; BodyCode=2;Code=3; Data=4; Const=5; Empty =6;
  859. BEGIN
  860. IF block.fixed THEN RETURN Fixed END;
  861. IF block.type = ObjectFile.InitCode THEN RETURN InitCode END;
  862. IF block.type = ObjectFile.BodyCode THEN RETURN Code END; (* BodyCode does not necessarily have to be in front of code *)
  863. IF block.GetSize () = 0 THEN RETURN Empty END;
  864. IF block.type = ObjectFile.Code THEN RETURN Code END;
  865. IF block.type = ObjectFile.Data THEN RETURN Code END;
  866. IF block.type = ObjectFile.Const THEN RETURN Code END;
  867. HALT(100); (* undefined type *)
  868. END GetPriority;
  869. PROCEDURE CopySections*(from, to: Sections.SectionList);
  870. VAR section, copy: IntermediateCode.Section; i,j: LONGINT; s: Sections.Section; instruction: IntermediateCode.Instruction;
  871. BEGIN
  872. FOR i := 0 TO from.Length()-1 DO
  873. s := from.GetSection(i);
  874. section := s(IntermediateCode.Section);
  875. copy := IntermediateCode.NewSection(to, section.type, section.name, NIL, FALSE);
  876. copy.SetBitsPerUnit(section.bitsPerUnit);
  877. copy.SetPositionOrAlignment(section.fixed, section.positionOrAlignment);
  878. copy.SetFingerprint(section.fingerprint);
  879. copy.SetPriority(section.priority);
  880. FOR j := 0 TO section.pc-1 DO
  881. instruction := section.instructions[j];
  882. copy.Emit(instruction);
  883. END;
  884. END;
  885. END CopySections;
  886. (*
  887. PROCEDURE LinkActiveCells*(activeCellsSpecification: ActiveCells.Specification; backend: Backend.Backend; objectFileFormat: Formats.ObjectFileFormat): BOOLEAN;
  888. TYPE
  889. LinkerObject= OBJECT
  890. VAR
  891. specification: ActiveCells.Specification;
  892. backend: Backend.Backend;
  893. diagnostics: Diagnostics.Diagnostics;
  894. irLinker: Linker;
  895. objectFileFormat: Formats.ObjectFileFormat;
  896. error: BOOLEAN;
  897. system: Global.System;
  898. PROCEDURE &Init(activeCellsSpecification: ActiveCells.Specification; b: Backend.Backend; objectFileFormat: Formats.ObjectFileFormat);
  899. BEGIN
  900. error := FALSE;
  901. SELF.specification := activeCellsSpecification;
  902. SELF.backend := b;
  903. SELF.diagnostics := specification.diagnostics;
  904. IF diagnostics = NIL THEN diagnostics := Basic.GetDefaultDiagnostics() END;
  905. SELF.objectFileFormat := objectFileFormat;
  906. NEW(irLinker, specification.diagnostics, backend, ""); (* TODO: pass an optional path as third parameter *)
  907. IF ~irLinker.LoadModule(backend(IntermediateCode.IntermediateBackend).runtimeModuleName, TRUE) THEN
  908. error := TRUE;
  909. Basic.Error(diagnostics, backend(IntermediateCode.IntermediateBackend).runtimeModuleName,Diagnostics.Invalid, Diagnostics.Invalid, "could not load ir file");
  910. END;
  911. IF ~irLinker.LoadModule(specification.name,TRUE) THEN
  912. error := TRUE;
  913. Basic.Error(diagnostics, specification.name,Diagnostics.Invalid, Diagnostics.Invalid, "could not load ir file");
  914. END;
  915. backend := irLinker.backend;
  916. system := backend.system;
  917. END Init;
  918. PROCEDURE LinkInstance(instance: ActiveCells.Instance): BOOLEAN;
  919. VAR
  920. codeFileName, dataFileName: Files.FileName;
  921. typeName, instanceName, linkRoot: SectionName;
  922. code, data: StaticLinker.Arrangement; linker: GenericLinker.Linker;
  923. i: LONGINT;
  924. logFile: Files.File; linkerLog: Files.Writer;
  925. type: ActiveCells.Type;
  926. msg: MessageString;
  927. objectFileExtension: ARRAY 32 OF CHAR;
  928. instructionMemorySize, dataMemorySize: LONGINT;
  929. parameter: ActiveCells.Parameter;
  930. value: SyntaxTree.Value;
  931. pooledName: Basic.SegmentedName;
  932. error : BOOLEAN;
  933. CONST MinimalStackSize=64;
  934. BEGIN
  935. error := FALSE;
  936. type := instance.instanceType;
  937. type.GetFullName(typeName,NIL);
  938. instance.GetFullName(instanceName,NIL);
  939. IF TraceLinking THEN
  940. D.String("assembling instance "); D.String(instanceName); D.String(" of type "); D.String(typeName); D.Ln;
  941. END;
  942. IF instance.IsEngine() THEN
  943. IF TraceLinking THEN
  944. D.String("instance "); D.String(instanceName); D.String(" is engine "); D.Ln;
  945. END;
  946. RETURN TRUE;
  947. END;
  948. backend.SetCapabilities(instance.capabilities);
  949. irLinker.MarkReachabilityOfAll(FALSE);
  950. COPY(typeName, linkRoot);
  951. Strings.Append(linkRoot,".@BodyStub");
  952. irLinker.MarkAsReachableByName(linkRoot);
  953. irLinker.PatchStackSize(typeName, instance.dataMemorySize);
  954. FOR i := 0 TO instance.parameters.Length()-1 DO
  955. parameter := instance.parameters.GetParameter(i);
  956. IF parameter.parameterType = 0 THEN (* Boolean *)
  957. value := SyntaxTree.NewBooleanValue(-1, parameter.boolean); value.SetType(system.booleanType);
  958. ELSE
  959. value := SyntaxTree.NewIntegerValue(-1, parameter.integer); value.SetType(system.integerType);
  960. END;
  961. Basic.ToSegmentedName(parameter.name, pooledName);
  962. irLinker.PatchValueInSection(pooledName,value);
  963. END;
  964. IF error THEN RETURN FALSE END;
  965. objectFileFormat.GetExtension(objectFileExtension);
  966. irLinker.PrearrangeReachableDataSections;
  967. IF ~irLinker.GenerateObjectFile(objectFileFormat, specification.log, instanceName) THEN
  968. Basic.Error(diagnostics, specification.name,Diagnostics.Invalid, Diagnostics.Invalid, "could not generate object file");
  969. RETURN FALSE
  970. END;
  971. IF TraceLinking THEN
  972. D.String("assembling instance done. "); D.Ln;
  973. END;
  974. NEW (code, 0); NEW (data, 0);
  975. COPY(instanceName, msg); Strings.Append(msg,".log"); logFile := Files.New(msg);
  976. IF logFile # NIL THEN NEW(linkerLog,logFile,0) ELSE logFile := NIL END;
  977. NEW (linker, specification.diagnostics, linkerLog, GenericLinker.UseInitCode, code, data);
  978. linker.SetLinkRoot("" (* linkRoot *)); (* take all initcode sections *)
  979. StaticLinker.ReadObjectFile(instanceName, "",objectFileExtension,linker);
  980. (* do linking after having read in all blocks to account for potential constraints *)
  981. IF ~linker.error THEN linker.Link; END;
  982. system := backend.GetSystem();
  983. instructionMemorySize := instance.instructionMemorySize;
  984. dataMemorySize := instance.dataMemorySize;
  985. IF instructionMemorySize = 0 THEN
  986. instructionMemorySize := type.instructionMemorySize
  987. END;
  988. IF dataMemorySize = 0 THEN
  989. dataMemorySize := type.dataMemorySize
  990. END;
  991. IF (instructionMemorySize > 0) & (instructionMemorySize < code.SizeInBits() DIV system.codeUnit) THEN
  992. Basic.Error(diagnostics, instanceName,Diagnostics.Invalid, Diagnostics.Invalid, "specified instruction memory size too small");
  993. error := TRUE;
  994. ELSIF instructionMemorySize = 0 THEN
  995. instructionMemorySize := code.SizeInBits() DIV system.codeUnit;
  996. END;
  997. dataMemorySize := MAX(data.SizeInBits() DIV system.dataUnit, dataMemorySize);
  998. instance.SetInstructionMemorySize(instructionMemorySize);
  999. instance.SetDataMemorySize(dataMemorySize);
  1000. IF (dataMemorySize - data.SizeInBits() DIV system.dataUnit) < MinimalStackSize THEN
  1001. Basic.Error(diagnostics, specification.name,Diagnostics.Invalid, Diagnostics.Invalid, "specified data memory size too small");
  1002. error := TRUE;
  1003. END;
  1004. Files.JoinExtension(instanceName,ActiveCells.CodeFileExtension,codeFileName);
  1005. Files.JoinExtension(instanceName,ActiveCells.DataFileExtension,dataFileName);
  1006. IF ~linker.error THEN
  1007. StaticLinker.WriteOutputFile (code, codeFileName, linker, StaticLinker.WriteTRMCodeFile);
  1008. StaticLinker.WriteOutputFile (data, dataFileName, linker, StaticLinker.WriteTRMDataFile);
  1009. IF linkerLog # NIL THEN linkerLog.Update; Files.Register(logFile) END;
  1010. IF specification.log # NIL THEN
  1011. specification.log.String(instanceName);
  1012. specification.log.String(" linked. IM = ");specification.log.Int(instructionMemorySize,1);
  1013. specification.log.String(" (used: "); specification.log.Int(code.SizeInBits() DIV system.codeUnit,1);
  1014. specification.log.String("), DM = "); specification.log.Int(dataMemorySize,1);
  1015. specification.log.String(" (used: "); specification.log.Int(data.SizeInBits() DIV system.dataUnit,1);
  1016. specification.log.String(")");
  1017. specification.log.Ln; specification.log.Update;
  1018. specification.log.String("generated code file: ");specification.log.String(codeFileName); specification.log.Ln;
  1019. specification.log.String("generated data file: ");specification.log.String(dataFileName); specification.log.Ln;
  1020. END;
  1021. ELSE
  1022. msg := "could not link ";
  1023. Strings.Append(msg,linkRoot);
  1024. Basic.Error(diagnostics, "",Diagnostics.Invalid, Diagnostics.Invalid, msg);
  1025. END;
  1026. RETURN ~linker.error & ~error
  1027. END LinkInstance;
  1028. END LinkerObject;
  1029. VAR obj: LinkerObject; spec: ActiveCells.Specification;
  1030. BEGIN
  1031. spec := ActiveCells.Clone(activeCellsSpecification)(ActiveCells.Specification);
  1032. ActiveCells.FlattenNetwork(spec);
  1033. NEW(obj,spec,backend,objectFileFormat);
  1034. IF obj.error THEN RETURN FALSE END;
  1035. RETURN spec.ForEachInstanceDo(obj.LinkInstance);
  1036. END LinkActiveCells;
  1037. *)
  1038. PROCEDURE Link*(context: Commands.Context);
  1039. VAR
  1040. input: Streams.Reader;
  1041. diagnostics: Diagnostics.StreamDiagnostics;
  1042. defaultBackend: Backend.Backend;
  1043. objectFileFormat: Formats.ObjectFileFormat;
  1044. filename, name, targetFile: Files.FileName;
  1045. assemblinker: Linker;
  1046. error, result, parsed: BOOLEAN;
  1047. options:Options.Options;
  1048. position: LONGINT;
  1049. moduleName: SyntaxTree.IdentifierString;
  1050. PROCEDURE Error(CONST error: ARRAY OF CHAR);
  1051. BEGIN
  1052. IF diagnostics # NIL THEN
  1053. Basic.Error(diagnostics, "",Basic.invalidPosition, error);
  1054. END;
  1055. END Error;
  1056. BEGIN
  1057. input := context.arg;
  1058. NEW(diagnostics, context.out);
  1059. result := TRUE;
  1060. NEW(options);
  1061. options.Add("b","backend",Options.String);
  1062. options.Add(0X, "objectFile", Options.String);
  1063. options.Add(0X, "targetFile", Options.String);
  1064. position := input.Pos();
  1065. parsed := options.Parse(input,NIL);
  1066. IF options.GetString("b", name) THEN
  1067. IF name = "" THEN defaultBackend := NIL
  1068. ELSE
  1069. defaultBackend := Backend.GetBackendByName(name);
  1070. IF (defaultBackend = NIL) THEN
  1071. Error("backend could not be installed"); result := FALSE;
  1072. END;
  1073. END;
  1074. ELSE defaultBackend := Backend.GetBackendByName(DefaultBackend);
  1075. IF defaultBackend = NIL THEN Error("default backend could not be installed"); result := FALSE END;
  1076. END;
  1077. IF options.GetString("objectFile",name) THEN
  1078. IF name = "" THEN objectFileFormat := NIL
  1079. ELSE
  1080. objectFileFormat := Formats.GetObjectFileFormat(name);
  1081. IF objectFileFormat = NIL THEN Error("object file format could not be installed"); result := FALSE END;
  1082. END;
  1083. ELSIF defaultBackend # NIL THEN
  1084. objectFileFormat := defaultBackend.DefaultObjectFileFormat();
  1085. END;
  1086. IF defaultBackend # NIL THEN defaultBackend.DefineOptions (options); END;
  1087. IF objectFileFormat # NIL THEN objectFileFormat.DefineOptions(options); END;
  1088. IF result & ~parsed THEN
  1089. options.Clear;
  1090. input.SetPos(position);
  1091. result := options.Parse(input,context.error)
  1092. END;
  1093. IF result THEN
  1094. IF defaultBackend # NIL THEN defaultBackend.GetOptions (options) END;
  1095. IF objectFileFormat # NIL THEN objectFileFormat.GetOptions(options) END;
  1096. IF ~options.GetString("targetFile",targetFile) THEN targetFile := "" END;
  1097. END;
  1098. error := ~result;
  1099. IF targetFile # "" THEN
  1100. NEW(assemblinker, diagnostics, defaultBackend);
  1101. END;
  1102. WHILE Basic.GetStringParameter(input,filename) & ~error DO
  1103. IF targetFile = "" THEN NEW(assemblinker, diagnostics, defaultBackend) END;
  1104. IF assemblinker.LoadModule(filename, FALSE) THEN
  1105. assemblinker.MarkReachabilityOfAll(TRUE);
  1106. FileNameToModuleName(filename, moduleName);
  1107. IF (targetFile = "") & assemblinker.GenerateObjectFile(objectFileFormat, context.out, moduleName) THEN
  1108. Basic.Information(diagnostics, filename, Basic.invalidPosition, "done.")
  1109. ELSIF targetFile # "" THEN
  1110. Basic.Information(diagnostics, filename, Basic.invalidPosition, "loaded.")
  1111. ELSE
  1112. error := TRUE
  1113. END
  1114. ELSE
  1115. error := TRUE
  1116. END
  1117. END;
  1118. IF ~error & (targetFile # "") THEN
  1119. assemblinker.PrearrangeReachableDataSections;
  1120. IF assemblinker.GenerateObjectFile(objectFileFormat, context.out, targetFile)
  1121. THEN
  1122. Basic.Information(diagnostics, targetFile, Basic.invalidPosition, "generated.")
  1123. ELSE error := FALSE
  1124. END;
  1125. END;
  1126. END Link;
  1127. PROCEDURE WriteCodeAndDataFiles*(CONST instanceName: ARRAY OF CHAR; CONST codeFileExtension, dataFileExtension: ARRAY OF CHAR; objectFile: Formats.ObjectFileFormat; VAR instructionMemorySize, dataMemorySize: LONGINT; backend: Backend.Backend; diagnostics: Diagnostics.Diagnostics; log:Streams.Writer): BOOLEAN;
  1128. VAR code, data: StaticLinker.Arrangement; linker: GenericLinker.Linker; linkerLog: Files.Writer;
  1129. logFile: Files.File;
  1130. objectFileExtension: ARRAY 32 OF CHAR;
  1131. error : BOOLEAN;
  1132. fileName, codeFileName, dataFileName: Files.FileName;
  1133. system: Global.System;
  1134. msg: ARRAY 256 OF CHAR;
  1135. CONST MinimalStackSize = 64;
  1136. (*CONST CodeFileExtension="code"; DataFileExtension="data";*)
  1137. BEGIN
  1138. error := FALSE;
  1139. NEW (code, 0); NEW (data, 0);
  1140. COPY(instanceName, fileName); Strings.Append(fileName,".log"); logFile := Files.New(fileName);
  1141. IF logFile # NIL THEN NEW(linkerLog,logFile,0) ELSE logFile := NIL END;
  1142. NEW (linker, diagnostics, linkerLog, GenericLinker.UseInitCode, code, data);
  1143. StaticLinker.ReadObjectFile(instanceName, "",objectFile.extension, linker, NIL);
  1144. (* do linking after having read in all blocks to account for potential constraints *)
  1145. IF ~linker.error THEN linker.Link; END;
  1146. system := backend.GetSystem();
  1147. IF (instructionMemorySize > 0) & (instructionMemorySize < code.SizeInBits() DIV system.codeUnit) THEN
  1148. Basic.Error(diagnostics, instanceName, Basic.invalidPosition, "specified instruction memory size too small");
  1149. error := TRUE;
  1150. ELSIF instructionMemorySize = 0 THEN
  1151. instructionMemorySize := code.SizeInBits() DIV system.codeUnit;
  1152. END;
  1153. dataMemorySize := MAX(data.SizeInBits() DIV system.dataUnit, dataMemorySize);
  1154. IF (dataMemorySize - data.SizeInBits() DIV system.dataUnit) < MinimalStackSize THEN
  1155. Basic.Error(diagnostics, instanceName,Basic.invalidPosition, "specified data memory size too small");
  1156. error := TRUE;
  1157. END;
  1158. Files.JoinExtension(instanceName,codeFileExtension,codeFileName);
  1159. Files.JoinExtension(instanceName,dataFileExtension,dataFileName);
  1160. IF ~linker.error THEN
  1161. StaticLinker.WriteOutputFile (code, codeFileName, linker, StaticLinker.WriteTRMCodeFile);
  1162. StaticLinker.WriteOutputFile (data, dataFileName, linker, StaticLinker.WriteTRMDataFile);
  1163. IF linkerLog # NIL THEN linkerLog.Update; Files.Register(logFile) END;
  1164. IF log # NIL THEN
  1165. log.String(instanceName);
  1166. log.String(" linked. IM = ");log.Int(instructionMemorySize,1);
  1167. log.String(" (used: "); log.Int(code.SizeInBits() DIV system.codeUnit,1);
  1168. log.String("), DM = "); log.Int(dataMemorySize,1);
  1169. log.String(" (used: "); log.Int(data.SizeInBits() DIV system.dataUnit,1);
  1170. log.String(")");
  1171. log.Ln; log.Update;
  1172. log.String("generated code file: ");log.String(codeFileName); log.Ln;
  1173. log.String("generated data file: ");log.String(dataFileName); log.Ln;
  1174. END;
  1175. ELSE
  1176. msg := "could not link ";
  1177. Strings.Append(msg,instanceName);
  1178. Basic.Error(diagnostics, "",Basic.invalidPosition, msg);
  1179. END;
  1180. RETURN ~linker.error & ~error
  1181. END WriteCodeAndDataFiles;
  1182. (* to link active cells
  1183. - load all intermediate code files and collect all sections in one object
  1184. - for each cell instance
  1185. - find body stub by name of cell type
  1186. - find all descending sections recursively (!! may depend on backend needs !)
  1187. - add sections for ports and properties
  1188. - assemble, generate gof file
  1189. - link gof file
  1190. - ir code / data units depend on section type, do not necessarily have to be stored
  1191. *)
  1192. PROCEDURE Test*(context: Commands.Context);
  1193. VAR
  1194. input: Streams.Reader;
  1195. diagnostics: Diagnostics.StreamDiagnostics;
  1196. defaultBackend: Backend.Backend;
  1197. objectFileFormat: Formats.ObjectFileFormat;
  1198. name, typeName, instanceName: Files.FileName;
  1199. result, parsed: BOOLEAN;
  1200. options:Options.Options;
  1201. position: LONGINT;
  1202. extension: SyntaxTree.IdentifierString;
  1203. linker: Linker;
  1204. PROCEDURE Error(CONST error: ARRAY OF CHAR);
  1205. BEGIN
  1206. IF diagnostics # NIL THEN
  1207. Basic.Error(diagnostics, "",Basic.invalidPosition, error);
  1208. END;
  1209. END Error;
  1210. BEGIN
  1211. input := context.arg;
  1212. NEW(diagnostics, context.out);
  1213. result := TRUE;
  1214. NEW(options);
  1215. options.Add("b","backend",Options.String);
  1216. options.Add(0X, "objectFile", Options.String);
  1217. options.Add(0X, "targetFile", Options.String);
  1218. options.Add(0X, "extension", Options.String);
  1219. position := input.Pos();
  1220. parsed := options.Parse(input,NIL);
  1221. IF options.GetString("b", name) THEN
  1222. IF name = "" THEN defaultBackend := NIL
  1223. ELSE
  1224. defaultBackend := Backend.GetBackendByName(name);
  1225. IF (defaultBackend = NIL) THEN
  1226. Error("backend could not be installed"); result := FALSE;
  1227. END;
  1228. END;
  1229. ELSE defaultBackend := Backend.GetBackendByName(DefaultBackend);
  1230. IF defaultBackend = NIL THEN Error("default backend could not be installed"); result := FALSE END;
  1231. END;
  1232. IF options.GetString("objectFile",name) THEN
  1233. IF name = "" THEN objectFileFormat := NIL
  1234. ELSE
  1235. objectFileFormat := Formats.GetObjectFileFormat(name);
  1236. IF objectFileFormat = NIL THEN Error("object file format could not be installed"); result := FALSE END;
  1237. END;
  1238. ELSIF defaultBackend # NIL THEN
  1239. objectFileFormat := defaultBackend.DefaultObjectFileFormat();
  1240. END;
  1241. IF defaultBackend # NIL THEN defaultBackend.DefineOptions (options); END;
  1242. IF objectFileFormat # NIL THEN objectFileFormat.DefineOptions(options); END;
  1243. IF result & ~parsed THEN
  1244. options.Clear;
  1245. input.SetPos(position);
  1246. result := options.Parse(input,context.error)
  1247. END;
  1248. IF result THEN
  1249. IF defaultBackend # NIL THEN defaultBackend.GetOptions (options) END;
  1250. IF objectFileFormat # NIL THEN objectFileFormat.GetOptions(options) END;
  1251. END;
  1252. IF ~options.GetString("extension",extension) THEN extension := "" END;
  1253. NEW(linker, diagnostics, defaultBackend);
  1254. IF Basic.GetStringParameter(input, typeName) & Basic.GetStringParameter(input, instanceName) THEN
  1255. IF linker.LinkPrefixed(typeName) THEN
  1256. linker.PrearrangeReachableDataSections;
  1257. IF linker.GenerateObjectFile(objectFileFormat, context.out, instanceName) THEN
  1258. context.out.String("generated "); context.out.String(instanceName);
  1259. context.out.String(objectFileFormat.extension);
  1260. context.out.Ln;
  1261. END;
  1262. END;
  1263. END;
  1264. (*
  1265. error := ~result;
  1266. IF targetFile # "" THEN
  1267. NEW(assemblinker, diagnostics, defaultBackend, "");
  1268. END;
  1269. IF Basic.GetStringParameter(input, name) THEN
  1270. SectionNameToFileName(name, filename);
  1271. TRACE(filename);
  1272. IF assemblinker.LoadModule(filename, FALSE) THEN
  1273. segmentedName := name;
  1274. assemblinker.MarkAsReachableStartingWith(segmentedName, {Sections.InitCodeSection, Sections.BodyCodeSection});
  1275. END;
  1276. END;
  1277. *)
  1278. (*
  1279. WHILE Basic.GetStringParameter(input,filename) & ~error DO
  1280. IF targetFile = "" THEN NEW(assemblinker, diagnostics, defaultBackend, "") END;
  1281. IF assemblinker.LoadModule(filename, FALSE) THEN
  1282. assemblinker.MarkReachabilityOfAll(TRUE);
  1283. FileNameToModuleName(filename, moduleName);
  1284. IF (targetFile = "") & assemblinker.GenerateObjectFile(objectFileFormat, context.out, moduleName) THEN
  1285. Basic.Information(diagnostics, filename, Diagnostics.Invalid, Diagnostics.Invalid, "done.")
  1286. ELSIF targetFile # "" THEN
  1287. Basic.Information(diagnostics, filename, Diagnostics.Invalid, Diagnostics.Invalid, "loaded.")
  1288. ELSE
  1289. error := TRUE
  1290. END
  1291. ELSE
  1292. error := TRUE
  1293. END
  1294. END;
  1295. *)
  1296. (*
  1297. IF ~error & (targetFile # "") THEN
  1298. assemblinker.PrearrangeReachableDataSections;
  1299. IF assemblinker.GenerateObjectFile(objectFileFormat, context.out, targetFile)
  1300. THEN
  1301. Basic.Information(diagnostics, targetFile, Diagnostics.Invalid, Diagnostics.Invalid, "generated.")
  1302. ELSE error := FALSE
  1303. END;
  1304. END;
  1305. *)
  1306. END Test;
  1307. END FoxIntermediateLinker.
  1308. SystemTools.FreeDownTo FoxIntermediateLinker ~
  1309. FoxIntermediateObjectFile.Show Test ~
  1310. FoxIntermediateLinker.Link -b=TRM --objectFile=Generic --targetFile=Test Test ~
  1311. FoxGenericObjectFile.Show Test.Gof ~
  1312. FoxIntermediateLinker.Test -b=TRM --objectFile=Generic --targetFile=Test --extension=.IroT TestActiveCells.TestCellnet.Controller MyController_Name ~
  1313. FoxGenericObjectFile.Show MyController_Name.Gof ~