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