FoxIntermediateLinker.Mod 56 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494
  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.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. FOR j := 0 TO section.pc-1 DO
  880. instruction := section.instructions[j];
  881. copy.Emit(instruction);
  882. END;
  883. END;
  884. END CopySections;
  885. (*
  886. PROCEDURE LinkActiveCells*(activeCellsSpecification: ActiveCells.Specification; backend: Backend.Backend; objectFileFormat: Formats.ObjectFileFormat): BOOLEAN;
  887. TYPE
  888. LinkerObject= OBJECT
  889. VAR
  890. specification: ActiveCells.Specification;
  891. backend: Backend.Backend;
  892. diagnostics: Diagnostics.Diagnostics;
  893. irLinker: Linker;
  894. objectFileFormat: Formats.ObjectFileFormat;
  895. error: BOOLEAN;
  896. system: Global.System;
  897. PROCEDURE &Init(activeCellsSpecification: ActiveCells.Specification; b: Backend.Backend; objectFileFormat: Formats.ObjectFileFormat);
  898. BEGIN
  899. error := FALSE;
  900. SELF.specification := activeCellsSpecification;
  901. SELF.backend := b;
  902. SELF.diagnostics := specification.diagnostics;
  903. IF diagnostics = NIL THEN diagnostics := Basic.GetDefaultDiagnostics() END;
  904. SELF.objectFileFormat := objectFileFormat;
  905. NEW(irLinker, specification.diagnostics, backend, ""); (* TODO: pass an optional path as third parameter *)
  906. IF ~irLinker.LoadModule(backend(IntermediateCode.IntermediateBackend).runtimeModuleName, TRUE) THEN
  907. error := TRUE;
  908. Basic.Error(diagnostics, backend(IntermediateCode.IntermediateBackend).runtimeModuleName,Diagnostics.Invalid, Diagnostics.Invalid, "could not load ir file");
  909. END;
  910. IF ~irLinker.LoadModule(specification.name,TRUE) THEN
  911. error := TRUE;
  912. Basic.Error(diagnostics, specification.name,Diagnostics.Invalid, Diagnostics.Invalid, "could not load ir file");
  913. END;
  914. backend := irLinker.backend;
  915. system := backend.system;
  916. END Init;
  917. PROCEDURE LinkInstance(instance: ActiveCells.Instance): BOOLEAN;
  918. VAR
  919. codeFileName, dataFileName: Files.FileName;
  920. typeName, instanceName, linkRoot: SectionName;
  921. code, data: StaticLinker.Arrangement; linker: GenericLinker.Linker;
  922. i: LONGINT;
  923. logFile: Files.File; linkerLog: Files.Writer;
  924. type: ActiveCells.Type;
  925. msg: MessageString;
  926. objectFileExtension: ARRAY 32 OF CHAR;
  927. instructionMemorySize, dataMemorySize: LONGINT;
  928. parameter: ActiveCells.Parameter;
  929. value: SyntaxTree.Value;
  930. pooledName: Basic.SegmentedName;
  931. error : BOOLEAN;
  932. CONST MinimalStackSize=64;
  933. BEGIN
  934. error := FALSE;
  935. type := instance.instanceType;
  936. type.GetFullName(typeName,NIL);
  937. instance.GetFullName(instanceName,NIL);
  938. IF TraceLinking THEN
  939. D.String("assembling instance "); D.String(instanceName); D.String(" of type "); D.String(typeName); D.Ln;
  940. END;
  941. IF instance.IsEngine() THEN
  942. IF TraceLinking THEN
  943. D.String("instance "); D.String(instanceName); D.String(" is engine "); D.Ln;
  944. END;
  945. RETURN TRUE;
  946. END;
  947. backend.SetCapabilities(instance.capabilities);
  948. irLinker.MarkReachabilityOfAll(FALSE);
  949. COPY(typeName, linkRoot);
  950. Strings.Append(linkRoot,".@BodyStub");
  951. irLinker.MarkAsReachableByName(linkRoot);
  952. irLinker.PatchStackSize(typeName, instance.dataMemorySize);
  953. FOR i := 0 TO instance.parameters.Length()-1 DO
  954. parameter := instance.parameters.GetParameter(i);
  955. IF parameter.parameterType = 0 THEN (* Boolean *)
  956. value := SyntaxTree.NewBooleanValue(-1, parameter.boolean); value.SetType(system.booleanType);
  957. ELSE
  958. value := SyntaxTree.NewIntegerValue(-1, parameter.integer); value.SetType(system.integerType);
  959. END;
  960. Basic.ToSegmentedName(parameter.name, pooledName);
  961. irLinker.PatchValueInSection(pooledName,value);
  962. END;
  963. IF error THEN RETURN FALSE END;
  964. objectFileFormat.GetExtension(objectFileExtension);
  965. irLinker.PrearrangeReachableDataSections;
  966. IF ~irLinker.GenerateObjectFile(objectFileFormat, specification.log, instanceName) THEN
  967. Basic.Error(diagnostics, specification.name,Diagnostics.Invalid, Diagnostics.Invalid, "could not generate object file");
  968. RETURN FALSE
  969. END;
  970. IF TraceLinking THEN
  971. D.String("assembling instance done. "); D.Ln;
  972. END;
  973. NEW (code, 0); NEW (data, 0);
  974. COPY(instanceName, msg); Strings.Append(msg,".log"); logFile := Files.New(msg);
  975. IF logFile # NIL THEN NEW(linkerLog,logFile,0) ELSE logFile := NIL END;
  976. NEW (linker, specification.diagnostics, linkerLog, GenericLinker.UseInitCode, code, data);
  977. linker.SetLinkRoot("" (* linkRoot *)); (* take all initcode sections *)
  978. StaticLinker.ReadObjectFile(instanceName, "",objectFileExtension,linker);
  979. (* do linking after having read in all blocks to account for potential constraints *)
  980. IF ~linker.error THEN linker.Link; END;
  981. system := backend.GetSystem();
  982. instructionMemorySize := instance.instructionMemorySize;
  983. dataMemorySize := instance.dataMemorySize;
  984. IF instructionMemorySize = 0 THEN
  985. instructionMemorySize := type.instructionMemorySize
  986. END;
  987. IF dataMemorySize = 0 THEN
  988. dataMemorySize := type.dataMemorySize
  989. END;
  990. IF (instructionMemorySize > 0) & (instructionMemorySize < code.SizeInBits() DIV system.codeUnit) THEN
  991. Basic.Error(diagnostics, instanceName,Diagnostics.Invalid, Diagnostics.Invalid, "specified instruction memory size too small");
  992. error := TRUE;
  993. ELSIF instructionMemorySize = 0 THEN
  994. instructionMemorySize := code.SizeInBits() DIV system.codeUnit;
  995. END;
  996. dataMemorySize := MAX(data.SizeInBits() DIV system.dataUnit, dataMemorySize);
  997. instance.SetInstructionMemorySize(instructionMemorySize);
  998. instance.SetDataMemorySize(dataMemorySize);
  999. IF (dataMemorySize - data.SizeInBits() DIV system.dataUnit) < MinimalStackSize THEN
  1000. Basic.Error(diagnostics, specification.name,Diagnostics.Invalid, Diagnostics.Invalid, "specified data memory size too small");
  1001. error := TRUE;
  1002. END;
  1003. Files.JoinExtension(instanceName,ActiveCells.CodeFileExtension,codeFileName);
  1004. Files.JoinExtension(instanceName,ActiveCells.DataFileExtension,dataFileName);
  1005. IF ~linker.error THEN
  1006. StaticLinker.WriteOutputFile (code, codeFileName, linker, StaticLinker.WriteTRMCodeFile);
  1007. StaticLinker.WriteOutputFile (data, dataFileName, linker, StaticLinker.WriteTRMDataFile);
  1008. IF linkerLog # NIL THEN linkerLog.Update; Files.Register(logFile) END;
  1009. IF specification.log # NIL THEN
  1010. specification.log.String(instanceName);
  1011. specification.log.String(" linked. IM = ");specification.log.Int(instructionMemorySize,1);
  1012. specification.log.String(" (used: "); specification.log.Int(code.SizeInBits() DIV system.codeUnit,1);
  1013. specification.log.String("), DM = "); specification.log.Int(dataMemorySize,1);
  1014. specification.log.String(" (used: "); specification.log.Int(data.SizeInBits() DIV system.dataUnit,1);
  1015. specification.log.String(")");
  1016. specification.log.Ln; specification.log.Update;
  1017. specification.log.String("generated code file: ");specification.log.String(codeFileName); specification.log.Ln;
  1018. specification.log.String("generated data file: ");specification.log.String(dataFileName); specification.log.Ln;
  1019. END;
  1020. ELSE
  1021. msg := "could not link ";
  1022. Strings.Append(msg,linkRoot);
  1023. Basic.Error(diagnostics, "",Diagnostics.Invalid, Diagnostics.Invalid, msg);
  1024. END;
  1025. RETURN ~linker.error & ~error
  1026. END LinkInstance;
  1027. END LinkerObject;
  1028. VAR obj: LinkerObject; spec: ActiveCells.Specification;
  1029. BEGIN
  1030. spec := ActiveCells.Clone(activeCellsSpecification)(ActiveCells.Specification);
  1031. ActiveCells.FlattenNetwork(spec);
  1032. NEW(obj,spec,backend,objectFileFormat);
  1033. IF obj.error THEN RETURN FALSE END;
  1034. RETURN spec.ForEachInstanceDo(obj.LinkInstance);
  1035. END LinkActiveCells;
  1036. *)
  1037. PROCEDURE Link*(context: Commands.Context);
  1038. VAR
  1039. input: Streams.Reader;
  1040. diagnostics: Diagnostics.StreamDiagnostics;
  1041. defaultBackend: Backend.Backend;
  1042. objectFileFormat: Formats.ObjectFileFormat;
  1043. filename, name, targetFile: Files.FileName;
  1044. assemblinker: Linker;
  1045. error, result, parsed: BOOLEAN;
  1046. options:Options.Options;
  1047. position: LONGINT;
  1048. moduleName: SyntaxTree.IdentifierString;
  1049. PROCEDURE Error(CONST error: ARRAY OF CHAR);
  1050. BEGIN
  1051. IF diagnostics # NIL THEN
  1052. Basic.Error(diagnostics, "",Basic.invalidPosition, error);
  1053. END;
  1054. END Error;
  1055. BEGIN
  1056. input := context.arg;
  1057. NEW(diagnostics, context.out);
  1058. result := TRUE;
  1059. NEW(options);
  1060. options.Add("b","backend",Options.String);
  1061. options.Add(0X, "objectFile", Options.String);
  1062. options.Add(0X, "targetFile", Options.String);
  1063. position := input.Pos();
  1064. parsed := options.Parse(input,NIL);
  1065. IF options.GetString("b", name) THEN
  1066. IF name = "" THEN defaultBackend := NIL
  1067. ELSE
  1068. defaultBackend := Backend.GetBackendByName(name);
  1069. IF (defaultBackend = NIL) THEN
  1070. Error("backend could not be installed"); result := FALSE;
  1071. END;
  1072. END;
  1073. ELSE defaultBackend := Backend.GetBackendByName(DefaultBackend);
  1074. IF defaultBackend = NIL THEN Error("default backend could not be installed"); result := FALSE END;
  1075. END;
  1076. IF options.GetString("objectFile",name) THEN
  1077. IF name = "" THEN objectFileFormat := NIL
  1078. ELSE
  1079. objectFileFormat := Formats.GetObjectFileFormat(name);
  1080. IF objectFileFormat = NIL THEN Error("object file format could not be installed"); result := FALSE END;
  1081. END;
  1082. ELSIF defaultBackend # NIL THEN
  1083. objectFileFormat := defaultBackend.DefaultObjectFileFormat();
  1084. END;
  1085. IF defaultBackend # NIL THEN defaultBackend.DefineOptions (options); END;
  1086. IF objectFileFormat # NIL THEN objectFileFormat.DefineOptions(options); END;
  1087. IF result & ~parsed THEN
  1088. options.Clear;
  1089. input.SetPos(position);
  1090. result := options.Parse(input,context.error)
  1091. END;
  1092. IF result THEN
  1093. IF defaultBackend # NIL THEN defaultBackend.GetOptions (options) END;
  1094. IF objectFileFormat # NIL THEN objectFileFormat.GetOptions(options) END;
  1095. IF ~options.GetString("targetFile",targetFile) THEN targetFile := "" END;
  1096. END;
  1097. error := ~result;
  1098. IF targetFile # "" THEN
  1099. NEW(assemblinker, diagnostics, defaultBackend);
  1100. END;
  1101. WHILE Basic.GetStringParameter(input,filename) & ~error DO
  1102. IF targetFile = "" THEN NEW(assemblinker, diagnostics, defaultBackend) END;
  1103. IF assemblinker.LoadModule(filename, FALSE) THEN
  1104. assemblinker.MarkReachabilityOfAll(TRUE);
  1105. FileNameToModuleName(filename, moduleName);
  1106. IF (targetFile = "") & assemblinker.GenerateObjectFile(objectFileFormat, context.out, moduleName) THEN
  1107. Basic.Information(diagnostics, filename, Basic.invalidPosition, "done.")
  1108. ELSIF targetFile # "" THEN
  1109. Basic.Information(diagnostics, filename, Basic.invalidPosition, "loaded.")
  1110. ELSE
  1111. error := TRUE
  1112. END
  1113. ELSE
  1114. error := TRUE
  1115. END
  1116. END;
  1117. IF ~error & (targetFile # "") THEN
  1118. assemblinker.PrearrangeReachableDataSections;
  1119. IF assemblinker.GenerateObjectFile(objectFileFormat, context.out, targetFile)
  1120. THEN
  1121. Basic.Information(diagnostics, targetFile, Basic.invalidPosition, "generated.")
  1122. ELSE error := FALSE
  1123. END;
  1124. END;
  1125. END Link;
  1126. 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;
  1127. VAR code, data: StaticLinker.Arrangement; linker: GenericLinker.Linker; linkerLog: Files.Writer;
  1128. logFile: Files.File;
  1129. objectFileExtension: ARRAY 32 OF CHAR;
  1130. error : BOOLEAN;
  1131. fileName, codeFileName, dataFileName: Files.FileName;
  1132. system: Global.System;
  1133. msg: ARRAY 256 OF CHAR;
  1134. CONST MinimalStackSize = 64;
  1135. (*CONST CodeFileExtension="code"; DataFileExtension="data";*)
  1136. BEGIN
  1137. error := FALSE;
  1138. NEW (code, 0); NEW (data, 0);
  1139. COPY(instanceName, fileName); Strings.Append(fileName,".log"); logFile := Files.New(fileName);
  1140. IF logFile # NIL THEN NEW(linkerLog,logFile,0) ELSE logFile := NIL END;
  1141. NEW (linker, diagnostics, linkerLog, GenericLinker.UseInitCode, code, data);
  1142. StaticLinker.ReadObjectFile(instanceName, "",objectFile.extension, linker, NIL);
  1143. (* do linking after having read in all blocks to account for potential constraints *)
  1144. IF ~linker.error THEN linker.Link; END;
  1145. system := backend.GetSystem();
  1146. IF (instructionMemorySize > 0) & (instructionMemorySize < code.SizeInBits() DIV system.codeUnit) THEN
  1147. Basic.Error(diagnostics, instanceName, Basic.invalidPosition, "specified instruction memory size too small");
  1148. error := TRUE;
  1149. ELSIF instructionMemorySize = 0 THEN
  1150. instructionMemorySize := code.SizeInBits() DIV system.codeUnit;
  1151. END;
  1152. dataMemorySize := MAX(data.SizeInBits() DIV system.dataUnit, dataMemorySize);
  1153. IF (dataMemorySize - data.SizeInBits() DIV system.dataUnit) < MinimalStackSize THEN
  1154. Basic.Error(diagnostics, instanceName,Basic.invalidPosition, "specified data memory size too small");
  1155. error := TRUE;
  1156. END;
  1157. Files.JoinExtension(instanceName,codeFileExtension,codeFileName);
  1158. Files.JoinExtension(instanceName,dataFileExtension,dataFileName);
  1159. IF ~linker.error THEN
  1160. StaticLinker.WriteOutputFile (code, codeFileName, linker, StaticLinker.WriteTRMCodeFile);
  1161. StaticLinker.WriteOutputFile (data, dataFileName, linker, StaticLinker.WriteTRMDataFile);
  1162. IF linkerLog # NIL THEN linkerLog.Update; Files.Register(logFile) END;
  1163. IF log # NIL THEN
  1164. log.String(instanceName);
  1165. log.String(" linked. IM = ");log.Int(instructionMemorySize,1);
  1166. log.String(" (used: "); log.Int(code.SizeInBits() DIV system.codeUnit,1);
  1167. log.String("), DM = "); log.Int(dataMemorySize,1);
  1168. log.String(" (used: "); log.Int(data.SizeInBits() DIV system.dataUnit,1);
  1169. log.String(")");
  1170. log.Ln; log.Update;
  1171. log.String("generated code file: ");log.String(codeFileName); log.Ln;
  1172. log.String("generated data file: ");log.String(dataFileName); log.Ln;
  1173. END;
  1174. ELSE
  1175. msg := "could not link ";
  1176. Strings.Append(msg,instanceName);
  1177. Basic.Error(diagnostics, "",Basic.invalidPosition, msg);
  1178. END;
  1179. RETURN ~linker.error & ~error
  1180. END WriteCodeAndDataFiles;
  1181. (* to link active cells
  1182. - load all intermediate code files and collect all sections in one object
  1183. - for each cell instance
  1184. - find body stub by name of cell type
  1185. - find all descending sections recursively (!! may depend on backend needs !)
  1186. - add sections for ports and properties
  1187. - assemble, generate gof file
  1188. - link gof file
  1189. - ir code / data units depend on section type, do not necessarily have to be stored
  1190. *)
  1191. PROCEDURE Test*(context: Commands.Context);
  1192. VAR
  1193. input: Streams.Reader;
  1194. diagnostics: Diagnostics.StreamDiagnostics;
  1195. defaultBackend: Backend.Backend;
  1196. objectFileFormat: Formats.ObjectFileFormat;
  1197. name, typeName, instanceName: Files.FileName;
  1198. result, parsed: BOOLEAN;
  1199. options:Options.Options;
  1200. position: LONGINT;
  1201. extension: SyntaxTree.IdentifierString;
  1202. linker: Linker;
  1203. PROCEDURE Error(CONST error: ARRAY OF CHAR);
  1204. BEGIN
  1205. IF diagnostics # NIL THEN
  1206. Basic.Error(diagnostics, "",Basic.invalidPosition, error);
  1207. END;
  1208. END Error;
  1209. BEGIN
  1210. input := context.arg;
  1211. NEW(diagnostics, context.out);
  1212. result := TRUE;
  1213. NEW(options);
  1214. options.Add("b","backend",Options.String);
  1215. options.Add(0X, "objectFile", Options.String);
  1216. options.Add(0X, "targetFile", Options.String);
  1217. options.Add(0X, "extension", Options.String);
  1218. position := input.Pos();
  1219. parsed := options.Parse(input,NIL);
  1220. IF options.GetString("b", name) THEN
  1221. IF name = "" THEN defaultBackend := NIL
  1222. ELSE
  1223. defaultBackend := Backend.GetBackendByName(name);
  1224. IF (defaultBackend = NIL) THEN
  1225. Error("backend could not be installed"); result := FALSE;
  1226. END;
  1227. END;
  1228. ELSE defaultBackend := Backend.GetBackendByName(DefaultBackend);
  1229. IF defaultBackend = NIL THEN Error("default backend could not be installed"); result := FALSE END;
  1230. END;
  1231. IF options.GetString("objectFile",name) THEN
  1232. IF name = "" THEN objectFileFormat := NIL
  1233. ELSE
  1234. objectFileFormat := Formats.GetObjectFileFormat(name);
  1235. IF objectFileFormat = NIL THEN Error("object file format could not be installed"); result := FALSE END;
  1236. END;
  1237. ELSIF defaultBackend # NIL THEN
  1238. objectFileFormat := defaultBackend.DefaultObjectFileFormat();
  1239. END;
  1240. IF defaultBackend # NIL THEN defaultBackend.DefineOptions (options); END;
  1241. IF objectFileFormat # NIL THEN objectFileFormat.DefineOptions(options); END;
  1242. IF result & ~parsed THEN
  1243. options.Clear;
  1244. input.SetPos(position);
  1245. result := options.Parse(input,context.error)
  1246. END;
  1247. IF result THEN
  1248. IF defaultBackend # NIL THEN defaultBackend.GetOptions (options) END;
  1249. IF objectFileFormat # NIL THEN objectFileFormat.GetOptions(options) END;
  1250. END;
  1251. IF ~options.GetString("extension",extension) THEN extension := "" END;
  1252. NEW(linker, diagnostics, defaultBackend);
  1253. IF Basic.GetStringParameter(input, typeName) & Basic.GetStringParameter(input, instanceName) THEN
  1254. IF linker.LinkPrefixed(typeName) THEN
  1255. linker.PrearrangeReachableDataSections;
  1256. IF linker.GenerateObjectFile(objectFileFormat, context.out, instanceName) THEN
  1257. context.out.String("generated "); context.out.String(instanceName);
  1258. context.out.String(objectFileFormat.extension);
  1259. context.out.Ln;
  1260. END;
  1261. END;
  1262. END;
  1263. (*
  1264. error := ~result;
  1265. IF targetFile # "" THEN
  1266. NEW(assemblinker, diagnostics, defaultBackend, "");
  1267. END;
  1268. IF Basic.GetStringParameter(input, name) THEN
  1269. SectionNameToFileName(name, filename);
  1270. TRACE(filename);
  1271. IF assemblinker.LoadModule(filename, FALSE) THEN
  1272. segmentedName := name;
  1273. assemblinker.MarkAsReachableStartingWith(segmentedName, {Sections.InitCodeSection, Sections.BodyCodeSection});
  1274. END;
  1275. END;
  1276. *)
  1277. (*
  1278. WHILE Basic.GetStringParameter(input,filename) & ~error DO
  1279. IF targetFile = "" THEN NEW(assemblinker, diagnostics, defaultBackend, "") END;
  1280. IF assemblinker.LoadModule(filename, FALSE) THEN
  1281. assemblinker.MarkReachabilityOfAll(TRUE);
  1282. FileNameToModuleName(filename, moduleName);
  1283. IF (targetFile = "") & assemblinker.GenerateObjectFile(objectFileFormat, context.out, moduleName) THEN
  1284. Basic.Information(diagnostics, filename, Diagnostics.Invalid, Diagnostics.Invalid, "done.")
  1285. ELSIF targetFile # "" THEN
  1286. Basic.Information(diagnostics, filename, Diagnostics.Invalid, Diagnostics.Invalid, "loaded.")
  1287. ELSE
  1288. error := TRUE
  1289. END
  1290. ELSE
  1291. error := TRUE
  1292. END
  1293. END;
  1294. *)
  1295. (*
  1296. IF ~error & (targetFile # "") THEN
  1297. assemblinker.PrearrangeReachableDataSections;
  1298. IF assemblinker.GenerateObjectFile(objectFileFormat, context.out, targetFile)
  1299. THEN
  1300. Basic.Information(diagnostics, targetFile, Diagnostics.Invalid, Diagnostics.Invalid, "generated.")
  1301. ELSE error := FALSE
  1302. END;
  1303. END;
  1304. *)
  1305. END Test;
  1306. END FoxIntermediateLinker.
  1307. SystemTools.FreeDownTo FoxIntermediateLinker ~
  1308. FoxIntermediateObjectFile.Show Test ~
  1309. FoxIntermediateLinker.Link -b=TRM --objectFile=Generic --targetFile=Test Test ~
  1310. FoxGenericObjectFile.Show Test.Gof ~
  1311. FoxIntermediateLinker.Test -b=TRM --objectFile=Generic --targetFile=Test --extension=.IroT TestActiveCells.TestCellnet.Controller MyController_Name ~
  1312. FoxGenericObjectFile.Show MyController_Name.Gof ~