FoxIntermediateLinker.Mod 57 KB

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