FoxIntermediateLinker.Mod 56 KB

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