FoxGenericObjectFile.Mod 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703
  1. MODULE FoxGenericObjectFile; (** AUTHOR "negelef"; PURPOSE "Generic Object File Writer"; *)
  2. IMPORT
  3. StringPool, Streams, Commands, Basic := FoxBasic, Formats := FoxFormats, Sections := FoxSections, IntermediateCode := FoxIntermediateCode,
  4. SyntaxTree := FoxSyntaxTree, BinaryCode := FoxBinaryCode,
  5. Fingerprinter := FoxFingerprinter, Files, Options, ObjectFile, SymbolFileFormat := FoxTextualSymbolFile, Strings, KernelLog, D := Debugging;
  6. CONST
  7. Version = 5;
  8. Trace = FALSE;
  9. TraceAliases = FALSE;
  10. WarnDuplicateFingerprints = FALSE;
  11. (* optimizations *)
  12. PatchFixups = TRUE; (* patch all fixups that can be processed during object file generation *)
  13. AliasOnlyExported = TRUE; (* create an alias only for exported sections *)
  14. DetailedStatistics = FALSE;
  15. VAR
  16. statModules, statModulesSize: LONGINT;
  17. statHeaders, statHeadersSize: LONGINT;
  18. TYPE
  19. SectionStat = POINTER TO RECORD
  20. name: ARRAY 64 OF CHAR;
  21. entries: LONGINT;
  22. size: LONGINT;
  23. END;
  24. VAR
  25. statPool : Basic.HashTableInt;
  26. TYPE ObjectFileFormat* = OBJECT (Formats.ObjectFileFormat)
  27. VAR binary: BOOLEAN; mergeSections: BOOLEAN;
  28. PROCEDURE & InitObjectFileFormat;
  29. BEGIN
  30. Init; SetExtension(ObjectFile.DefaultExtension);
  31. END InitObjectFileFormat;
  32. PROCEDURE Export* (module: Formats.GeneratedModule; symbolFileFormat: Formats.SymbolFileFormat): BOOLEAN;
  33. VAR fileName: Files.FileName; file: Files.File; writer: Files.Writer; fingerprinter: Fingerprinter.Fingerprinter; poolMap: ObjectFile.PoolMap;
  34. PROCEDURE ExportSection (section: IntermediateCode.Section): BOOLEAN;
  35. VAR name: ARRAY 256 OF CHAR; (* debugging *)
  36. BEGIN
  37. (*
  38. IF section.IsExternal() OR (section.symbol # NIL) & (section.symbol.scope # NIL) & (section.symbol.scope.ownerModule # module(Sections.Module).module) THEN
  39. (* nothing to do *)
  40. ELSE
  41. *)
  42. IF section.resolved = NIL THEN
  43. Basic.SegmentedNameToString(section.name, name);
  44. D.String('"section.resolved = NIL" for '); D.String(name); D.Ln;
  45. RETURN FALSE
  46. END;
  47. section.resolved.os.identifier.fingerprint := GetFingerprint (section, fingerprinter);
  48. CopyFixups (NIL, section.resolved, section.resolved, 0);
  49. ObjectFile.WriteSection(writer,section.resolved.os,binary, poolMap);
  50. (*
  51. END;
  52. *)
  53. RETURN TRUE
  54. END ExportSection;
  55. PROCEDURE MergeSections (sections: Sections.SectionList): BOOLEAN;
  56. VAR
  57. section: Sections.Section;
  58. i: LONGINT;
  59. sname: Basic.SegmentedName;
  60. codeAlign, dataAlign, constAlign: LONGINT;
  61. codeUnit, dataUnit, constUnit: LONGINT;
  62. resolved, codeSection, dataSection, constSection: BinaryCode.Section;
  63. alias: BinaryCode.Alias;
  64. irSection: IntermediateCode.Section;
  65. exported: BOOLEAN;
  66. BEGIN
  67. codeAlign := 0; dataAlign := 0; constAlign := 0;
  68. FOR i := 0 TO sections.Length() - 1 DO
  69. section := sections.GetSection(i);
  70. resolved := section(IntermediateCode.Section).resolved;
  71. IF resolved = NIL THEN RETURN FALSE END;
  72. IF (resolved # NIL) & (resolved.pc # 0) & (~resolved.os.fixed) THEN
  73. IF section.type = ObjectFile.Code THEN
  74. codeAlign := CommonAlignment(codeAlign, resolved.os.alignment);
  75. ASSERT((codeUnit=0) OR (codeUnit = resolved.os.unit));
  76. codeUnit := resolved.os.unit;
  77. ELSIF section.type = ObjectFile.Data THEN
  78. dataAlign := CommonAlignment(dataAlign, resolved.os.alignment);
  79. ASSERT((dataUnit=0) OR (dataUnit = resolved.os.unit));
  80. dataUnit := resolved.os.unit;
  81. ELSIF section.type = ObjectFile.Const THEN
  82. constAlign := CommonAlignment(constAlign, resolved.os.alignment);
  83. ASSERT((constUnit=0) OR (constUnit = resolved.os.unit));
  84. constUnit := resolved.os.unit;
  85. END;
  86. END;
  87. END;
  88. IF codeUnit > 0 THEN
  89. sname := module.moduleName;
  90. Basic.AppendToSegmentedName(sname,".@CodeSections");
  91. codeSection := BinaryCode.NewBinarySection(ObjectFile.Code, codeUnit, sname, FALSE, FALSE);
  92. codeSection.SetAlignment(FALSE,codeAlign);
  93. END;
  94. IF dataUnit > 0 THEN
  95. sname := module.moduleName;
  96. Basic.AppendToSegmentedName(sname,".@DataSections");
  97. dataSection := BinaryCode.NewBinarySection(ObjectFile.Data, dataUnit, sname, FALSE, FALSE);
  98. dataSection.SetAlignment(FALSE,dataAlign);
  99. END;
  100. IF constUnit > 0 THEN
  101. sname := module.moduleName;
  102. Basic.AppendToSegmentedName(sname,".@ConstSections");
  103. constSection := BinaryCode.NewBinarySection(ObjectFile.Const, constUnit, sname, FALSE, FALSE);
  104. constSection.SetAlignment(FALSE,constAlign);
  105. END;
  106. (*TRACE(codeAlign, dataAlign, constAlign);*)
  107. (*codeAlign := 0; dataAlign := 0; constAlign := 0;*)
  108. FOR i := 0 TO sections.Length() - 1 DO
  109. section := sections.GetSection(i);
  110. resolved := section(IntermediateCode.Section).resolved;
  111. exported := section(IntermediateCode.Section).exported;
  112. IF (resolved # NIL) & (resolved.pc # 0) & (~resolved.os.fixed) THEN
  113. IF section.type = ObjectFile.Code THEN
  114. IF resolved.os.alignment # 0 THEN
  115. codeSection.Align(resolved.os.alignment);
  116. END;
  117. resolved.os.identifier.fingerprint := GetFingerprint (section, fingerprinter);
  118. NEW(alias, resolved.os.identifier, codeSection.pc);
  119. IF ~AliasOnlyExported OR exported THEN codeSection.aliasList.AddAlias(alias) END;
  120. section(IntermediateCode.Section).SetAlias(codeSection, codeSection.pc);
  121. codeSection.CopyBits(resolved.os.bits,0, resolved.pc*codeUnit);
  122. ELSIF section.type = ObjectFile.Data THEN
  123. IF resolved.os.alignment # 0 THEN
  124. dataSection.Align(resolved.os.alignment);
  125. END;
  126. resolved.os.identifier.fingerprint := GetFingerprint (section, fingerprinter);
  127. NEW(alias, resolved.os.identifier, dataSection.pc);
  128. IF ~AliasOnlyExported OR exported THEN dataSection.aliasList.AddAlias(alias) END;
  129. section(IntermediateCode.Section).SetAlias(dataSection, dataSection.pc);
  130. dataSection.CopyBits(resolved.os.bits,0, resolved.pc*dataUnit );
  131. ELSIF section.type = ObjectFile.Const THEN
  132. IF resolved.os.alignment # 0 THEN
  133. constSection.Align(resolved.os.alignment);
  134. END;
  135. resolved.os.identifier.fingerprint := GetFingerprint (section, fingerprinter);
  136. NEW(alias, resolved.os.identifier, constSection.pc);
  137. IF ~AliasOnlyExported OR exported THEN constSection.aliasList.AddAlias(alias) END;
  138. section(IntermediateCode.Section).SetAlias(constSection, constSection.pc);
  139. constSection.CopyBits(resolved.os.bits,0, resolved.pc*constUnit);
  140. END;
  141. END;
  142. END;
  143. FOR i := 0 TO sections.Length() - 1 DO
  144. section := sections.GetSection(i);
  145. resolved := section(IntermediateCode.Section).resolved;
  146. exported := section(IntermediateCode.Section).exported;
  147. IF (section(IntermediateCode.Section).alias # NIL) THEN
  148. CopyFixups(sections, resolved, section(IntermediateCode.Section).alias, section(IntermediateCode.Section).aliasOffset);
  149. ELSE
  150. CopyFixups(sections, resolved, resolved,0);
  151. END;
  152. END;
  153. IF codeSection # NIL THEN
  154. UpdateAliases (codeSection, fingerprinter);
  155. irSection := IntermediateCode.NewSection(sections, SHORTINT(codeSection.os.type), codeSection.os.identifier.name, NIL, FALSE);
  156. irSection.SetResolved(codeSection);
  157. END;
  158. IF dataSection # NIL THEN
  159. UpdateAliases (dataSection, fingerprinter);
  160. irSection := IntermediateCode.NewSection(sections, SHORTINT(dataSection.os.type), dataSection.os.identifier.name, NIL, FALSE);
  161. irSection.SetResolved(dataSection);
  162. END;
  163. IF constSection # NIL THEN
  164. UpdateAliases (constSection, fingerprinter);
  165. irSection := IntermediateCode.NewSection(sections, SHORTINT(constSection.os.type), constSection.os.identifier.name, NIL, FALSE);
  166. irSection.SetResolved(constSection);
  167. END;
  168. RETURN TRUE;
  169. END MergeSections;
  170. PROCEDURE ExportSections (sections: Sections.SectionList): BOOLEAN;
  171. VAR
  172. section, test: Sections.Section;
  173. i, j: LONGINT;
  174. name: ObjectFile.SectionName;
  175. msg: ARRAY 256 OF CHAR;
  176. BEGIN
  177. FOR i := 0 TO sections.Length() - 1 DO
  178. section := sections.GetSection(i);
  179. IF (section(IntermediateCode.Section).resolved # NIL) & (section(IntermediateCode.Section).alias = NIL) THEN
  180. IF ~ExportSection(section(IntermediateCode.Section)) THEN RETURN FALSE END;
  181. IF WarnDuplicateFingerprints & (section(IntermediateCode.Section).resolved.os.identifier.fingerprint # 0) THEN
  182. FOR j := 0 TO i - 1 DO
  183. test := sections.GetSection(j);
  184. IF (test(IntermediateCode.Section).resolved # NIL)
  185. & (test(IntermediateCode.Section).resolved.os.identifier.fingerprint = section(IntermediateCode.Section).resolved.os.identifier.fingerprint) THEN
  186. msg := "duplicate fingerprints: ";
  187. ObjectFile.SegmentedNameToString(section(IntermediateCode.Section).resolved.os.identifier.name,name);
  188. Strings.Append(msg, name);
  189. Strings.Append(msg, ", ");
  190. ObjectFile.SegmentedNameToString(test(IntermediateCode.Section).resolved.os.identifier.name,name);
  191. Strings.Append(msg, name);
  192. Basic.Warning(diagnostics, module.moduleName,Basic.invalidPosition, msg);
  193. END
  194. END
  195. END
  196. END
  197. END;
  198. RETURN TRUE
  199. END ExportSections;
  200. PROCEDURE MakeStatistics(sections: Sections.SectionList);
  201. VAR i: LONGINT;
  202. section: Sections.Section;
  203. resolved: BinaryCode.Section;
  204. suffix: ARRAY 128 OF CHAR;
  205. index: StringPool.Index;
  206. any: ANY;
  207. sectionStat : SectionStat;
  208. BEGIN
  209. FOR i := 0 TO sections.Length()-1 DO
  210. section := sections.GetSection(i);
  211. resolved := section(IntermediateCode.Section).resolved;
  212. Basic.GetSuffix(section.name, suffix);
  213. IF (suffix[0] = "@") & ((suffix[1] # "c") OR (suffix[2] # "o")) THEN
  214. StringPool.GetIndex(suffix, index);
  215. any := statPool.Get(index);
  216. IF any = NIL THEN
  217. NEW(sectionStat);
  218. COPY(suffix, sectionStat.name);
  219. sectionStat.entries := 0;
  220. sectionStat.size := 0;
  221. statPool.Put(index, sectionStat);
  222. ELSE
  223. sectionStat := any(SectionStat);
  224. END;
  225. INC(sectionStat.entries);
  226. INC(sectionStat.size, resolved.pc);
  227. END;
  228. END;
  229. END MakeStatistics;
  230. PROCEDURE ExportModule (module: Sections.Module): BOOLEAN;
  231. VAR result: BOOLEAN; pos: LONGINT;
  232. offers, requires: ObjectFile.NameList;
  233. numImports: LONGINT;
  234. name: ObjectFile.SectionName;
  235. import: SyntaxTree.Import;
  236. BEGIN
  237. pos := writer.Pos();
  238. IF DetailedStatistics THEN
  239. MakeStatistics(module.allSections);
  240. END;
  241. IF mergeSections & ~MergeSections(module.allSections) THEN RETURN FALSE END;
  242. NEW (offers, 1); offers[0] := module.moduleName;
  243. IF module.module#NIL THEN
  244. import := module.module.moduleScope.firstImport;
  245. numImports := 0;
  246. WHILE import # NIL DO
  247. IF import.direct THEN INC(numImports) END;
  248. import := import.nextImport;
  249. END;
  250. NEW(requires, numImports);
  251. numImports := 0;
  252. import := module.module.moduleScope.firstImport;
  253. WHILE import # NIL DO
  254. IF import.direct THEN
  255. import.module.GetName(name);
  256. requires[numImports] := name;
  257. INC(numImports);
  258. END;
  259. import := import.nextImport;
  260. END;
  261. END;
  262. WriteHeader(writer,binary,module.allSections, poolMap, offers, requires, fingerprinter);
  263. INC(statHeaders); INC(statHeadersSize, writer.Pos()-pos);
  264. result := ExportSections (module.allSections);
  265. INC(statModules); INC(statModulesSize, writer.Pos()-pos);
  266. RETURN result
  267. END ExportModule;
  268. BEGIN
  269. IF Trace THEN D.String(">>> export generic object file"); D.Ln END;
  270. IF ~(module IS Sections.Module) THEN
  271. Basic.Error (diagnostics, module.moduleName, Basic.invalidPosition, "generated module format does not match object file format");
  272. RETURN FALSE;
  273. END;
  274. IF path # "" THEN Files.JoinPath (path, module.moduleName, fileName); ELSE COPY (module.moduleName, fileName); END;
  275. Files.JoinExtension (fileName, extension, fileName);
  276. IF Trace THEN D.String(">>> filename: "); D.String(fileName); D.Ln END;
  277. file := Files.New (fileName);
  278. IF file = NIL THEN
  279. Basic.Error(diagnostics, module.moduleName,Basic.invalidPosition, "failed to open object file");
  280. RETURN FALSE;
  281. END;
  282. NEW (fingerprinter);
  283. Files.OpenWriter (writer, file, 0);
  284. IF ExportModule (module(Sections.Module)) THEN
  285. writer.Update;
  286. Files.Register (file);
  287. RETURN TRUE;
  288. ELSE
  289. RETURN FALSE
  290. END
  291. END Export;
  292. PROCEDURE DefineOptions* (options: Options.Options);
  293. BEGIN
  294. options.Add(0X,"objectFileExtension",Options.String);
  295. options.Add(0X,"textualObjectFile",Options.Flag);
  296. options.Add(0X,"mergeSections",Options.Flag);
  297. END DefineOptions;
  298. PROCEDURE GetOptions* (options: Options.Options);
  299. VAR extension: Files.FileName;
  300. BEGIN
  301. IF options.GetString("objectFileExtension",extension) THEN
  302. SetExtension(extension);
  303. END;
  304. binary := ~options.GetFlag("textualObjectFile");
  305. mergeSections := options.GetFlag("mergeSections");
  306. END GetOptions;
  307. PROCEDURE DefaultSymbolFileFormat*(): Formats.SymbolFileFormat;
  308. BEGIN RETURN SymbolFileFormat.Get();
  309. END DefaultSymbolFileFormat;
  310. END ObjectFileFormat;
  311. PROCEDURE GetFingerprint (section: Sections.Section; fingerprinter: Fingerprinter.Fingerprinter): LONGINT;
  312. VAR fingerprint: SyntaxTree.Fingerprint; fp: LONGINT; string: Basic.SectionName;
  313. BEGIN
  314. IF section.fingerprint # 0 THEN
  315. fp := section.fingerprint
  316. ELSIF (section.symbol = NIL) OR (section.symbol.scope = NIL) THEN
  317. fp := 0;
  318. IF (section(IntermediateCode.Section).resolved # NIL) THEN
  319. Basic.SegmentedNameToString(section.name, string);
  320. Fingerprinter.FPString(fp, string)
  321. END
  322. ELSIF fingerprinter # NIL THEN
  323. fingerprint := fingerprinter.SymbolFP (section.symbol);
  324. fp := fingerprint.shallow;
  325. END;
  326. RETURN fp
  327. END GetFingerprint;
  328. PROCEDURE CheckAlias(sections: Sections.SectionList; VAR identifier: ObjectFile.Identifier; VAR offset: LONGINT);
  329. VAR section: Sections.Section; alias: BinaryCode.Section;
  330. BEGIN
  331. offset := 0;
  332. IF sections = NIL THEN RETURN END;
  333. section := sections.FindByName(identifier.name);
  334. IF (section # NIL) THEN
  335. alias := section(IntermediateCode.Section).alias;
  336. IF alias # NIL THEN
  337. offset := section(IntermediateCode.Section).aliasOffset;
  338. IF TraceAliases THEN
  339. Basic.WriteSegmentedName(D.Log, identifier.name); D.String(" => ");
  340. Basic.WriteSegmentedName(D.Log, alias.os.identifier.name);
  341. D.Ln;
  342. END;
  343. identifier := alias.os.identifier;
  344. END;
  345. END;
  346. END CheckAlias;
  347. PROCEDURE CopyFixups(sections: Sections.SectionList; from, to: BinaryCode.Section; offset: LONGINT);
  348. VAR fixup: BinaryCode.Fixup; i: INTEGER; index: LONGINT; fixupList: ObjectFile.Fixups; fixups: LONGINT;
  349. aliasSymbol: ObjectFile.Identifier; aliasOffset: LONGINT;
  350. PROCEDURE PatchFixup (fixup: BinaryCode.Fixup; fixupOffset, targetOffset: LONGINT);
  351. VAR target, address: ObjectFile.Unit; j: LONGINT;
  352. PROCEDURE PatchPattern (CONST pattern: ObjectFile.FixupPattern);
  353. BEGIN
  354. to.os.bits.SetBits (target * to.os.unit + pattern.offset, pattern.bits, address); address := ASH (address, -pattern.bits);
  355. END PatchPattern;
  356. PROCEDURE CheckBits(value: LONGINT; offset: LONGINT);
  357. VAR i, nobits,remainder: LONGINT; minval, maxval: ObjectFile.Unit; name: ObjectFile.SectionName; number: ARRAY 32 OF CHAR;
  358. BEGIN
  359. nobits := 0;
  360. FOR i := 0 TO fixup.patterns-1 DO
  361. INC(nobits,fixup.pattern[i].bits);
  362. END;
  363. remainder := ASH(address,-nobits);
  364. IF (nobits <32) & ((remainder > 0) OR (remainder < -1)) THEN
  365. IF fixup.mode = ObjectFile.Relative THEN (* negative values allowed *)
  366. maxval := ASH(1,nobits-1)-1; minval := -maxval-1
  367. ELSE
  368. minval := 0; maxval := ASH(1,nobits);
  369. END;
  370. ObjectFile.SegmentedNameToString(to.os.identifier.name,name);
  371. Strings.Append(name,":");
  372. Strings.IntToStr(offset,number);
  373. Strings.Append(name,number);
  374. D.String(name); D.String("fixup out of range"); D.Ln;
  375. HALT(100);
  376. END;
  377. END CheckBits;
  378. BEGIN
  379. target := fixupOffset + fixup.offset ;
  380. address := targetOffset + fixup.displacement;
  381. IF fixup.mode = ObjectFile.Relative THEN
  382. DEC(address,target)
  383. END;
  384. address := ASH (address, fixup.scale);
  385. CheckBits(address, fixup.offset);
  386. FOR j := 0 TO fixup.patterns-1 DO PatchPattern(fixup.pattern[j]) END;
  387. END PatchFixup;
  388. BEGIN
  389. fixup := from.fixupList.firstFixup; i := 0; fixups := to.os.fixups; fixupList := to.os.fixup;
  390. WHILE fixup # NIL DO
  391. (*! fingerprint := GetFingerprint(fixup.symbol, fingerprinter); *)
  392. aliasSymbol := fixup.symbol;
  393. CheckAlias(sections, aliasSymbol, aliasOffset);
  394. IF PatchFixups & (aliasSymbol.name = to.os.identifier.name) & (fixup.mode = BinaryCode.Relative) THEN
  395. PatchFixup(fixup, offset, aliasOffset);
  396. ELSE
  397. index := ObjectFile.AddFixup(fixups, fixupList, aliasSymbol.name, aliasSymbol.fingerprint, fixup.mode,fixup.scale, fixup.patterns, fixup.pattern);
  398. ObjectFile.AddPatch(fixupList[index].patches, fixupList[index].patch, fixup.displacement+aliasOffset, fixup.offset+offset);
  399. END;
  400. fixup := fixup.nextFixup; INC (i);
  401. END;
  402. ObjectFile.SetFixups(to.os, fixups, fixupList);
  403. from.fixupList.InitFixupList; (* delete the source list *)
  404. END CopyFixups;
  405. PROCEDURE UpdateAliases (section: BinaryCode.Section; fingerprinter: Fingerprinter.Fingerprinter);
  406. VAR alias: BinaryCode.Alias; i: INTEGER; aliasList: ObjectFile.Aliases; aliases: LONGINT; index: LONGINT;
  407. BEGIN
  408. alias := section.aliasList.firstAlias; i := 0; aliases := 0; aliasList := NIL;
  409. WHILE alias # NIL DO
  410. (*! fingerprint := GetFingerprint(alias.symbol, fingerprinter); *)
  411. index := ObjectFile.AddAlias(aliases, aliasList, alias.identifier.name, alias.identifier.fingerprint, alias.offset);
  412. alias := alias.nextAlias; INC (i);
  413. END;
  414. ObjectFile.SetAliases(section.os, aliases, aliasList);
  415. section.aliasList.InitAliasList;
  416. END UpdateAliases;
  417. PROCEDURE Get*(): Formats.ObjectFileFormat;
  418. VAR objectFileFormat: ObjectFileFormat;
  419. BEGIN NEW(objectFileFormat); RETURN objectFileFormat
  420. END Get;
  421. PROCEDURE ReadHeader(reader: Streams.Reader; VAR binary: BOOLEAN; VAR poolMap: ObjectFile.PoolMap; VAR offers, requires: ObjectFile.NameList): LONGINT;
  422. VAR ch: CHAR; string: ARRAY 32 OF CHAR;
  423. VAR version: LONGINT;
  424. BEGIN
  425. reader.String(string);
  426. binary := string="FoxOFB";
  427. IF ~binary THEN ASSERT(string="FoxOFT") END;
  428. reader.SkipWhitespace;
  429. reader.Char(ch); ASSERT(ch='v');
  430. reader.Int(version,FALSE);
  431. IF version < Version THEN KernelLog.String("warning: old object file encountered, recompile all sources"); KernelLog.Ln END;
  432. reader.Char(ch); ASSERT(ch='.');
  433. IF ~binary THEN reader.SkipWhitespace
  434. ELSE
  435. NEW(poolMap,64);
  436. poolMap.Read(reader);
  437. END;
  438. offers := NIL;
  439. requires := NIL;
  440. IF version >= 4 THEN
  441. IF ~binary THEN
  442. reader.String(string); ObjectFile.ReadNameList(reader, offers, binary, poolMap);
  443. reader.SkipWhitespace;
  444. reader.String(string); ObjectFile.ReadNameList(reader, requires, binary, poolMap);
  445. reader.SkipWhitespace;
  446. ELSE
  447. ObjectFile.ReadNameList(reader, offers, binary, poolMap);
  448. ObjectFile.ReadNameList(reader, requires, binary, poolMap);
  449. END
  450. END;
  451. RETURN version;
  452. END ReadHeader;
  453. PROCEDURE WriteHeader(writer: Streams.Writer; binary: BOOLEAN; sections: Sections.SectionList; VAR poolMap: ObjectFile.PoolMap; offers, requires: ObjectFile.NameList; fingerprinter:Fingerprinter.Fingerprinter);
  454. VAR i: LONGINT; section: Sections.Section;
  455. PROCEDURE ProcessSection(section: IntermediateCode.Section);
  456. VAR i: LONGINT; fixup: BinaryCode.Fixup; alias: BinaryCode.Alias;
  457. BEGIN
  458. IF (section.resolved # NIL) & (section.alias = NIL) THEN
  459. poolMap.PutSegmentedName(section.resolved.os.identifier.name);
  460. (* for those sections that have been already resolved *)
  461. FOR i := 0 TO section.resolved.os.fixups-1 DO
  462. poolMap.PutSegmentedName(section.resolved.os.fixup[i].identifier.name);
  463. END;
  464. FOR i := 0 TO section.resolved.os.aliases-1 DO
  465. poolMap.PutSegmentedName(section.resolved.os.alias[i].identifier.name);
  466. END;
  467. fixup := section.resolved.fixupList.firstFixup; i := 0;
  468. WHILE fixup # NIL DO
  469. poolMap.PutSegmentedName(fixup.symbol.name);
  470. fixup := fixup.nextFixup;
  471. END;
  472. alias:= section.resolved.aliasList.firstAlias; i := 0;
  473. WHILE alias # NIL DO
  474. poolMap.PutSegmentedName(alias.identifier.name);
  475. alias := alias.nextAlias;
  476. END;
  477. END;
  478. END ProcessSection;
  479. PROCEDURE NameList(CONST names: ObjectFile.NameList);
  480. BEGIN
  481. IF names # NIL THEN
  482. FOR i := 0 TO LEN(names)-1 DO
  483. poolMap.PutSegmentedName(names[i]);
  484. END;
  485. END;
  486. END NameList;
  487. BEGIN
  488. IF binary THEN writer.String("FoxOFB");
  489. ELSE writer.String("FoxOFT");
  490. END;
  491. writer.Char(' ');
  492. writer.Char('v'); writer.Int(Version,0); writer.Char(".");
  493. IF ~binary THEN
  494. writer.Ln;
  495. writer.String("offers "); ObjectFile.WriteNameList(writer, offers, binary, poolMap);
  496. writer.String("requires "); ObjectFile.WriteNameList(writer, requires, binary, poolMap);
  497. writer.Ln;
  498. ELSE
  499. NEW(poolMap,512);
  500. poolMap.BeginWriting(writer);
  501. FOR i := 0 TO sections.Length()-1 DO
  502. section := sections.GetSection(i);
  503. ProcessSection(section(IntermediateCode.Section));
  504. END;
  505. NameList(offers); NameList(requires);
  506. poolMap.EndWriting;
  507. ObjectFile.WriteNameList(writer, offers, binary, poolMap);
  508. ObjectFile.WriteNameList(writer, requires, binary, poolMap);
  509. (*
  510. FOR i := 0 TO fixups-1 DO
  511. D.String("fingerprint: "); Basic.WriteSegmentedName(D.Log, fixupList[i].identifier.name); D.Ln;
  512. END;
  513. *)
  514. END;
  515. END WriteHeader;
  516. PROCEDURE GCD(a,b: LONGINT): LONGINT;
  517. VAR h: LONGINT;
  518. BEGIN
  519. WHILE b # 0 DO
  520. h := a MOD b;
  521. a := b;
  522. b := h;
  523. END;
  524. RETURN a
  525. END GCD;
  526. PROCEDURE SCM(a,b: LONGINT): LONGINT;
  527. BEGIN
  528. RETURN a*b DIV GCD(a,b)
  529. END SCM;
  530. PROCEDURE CommonAlignment(a,b: LONGINT): LONGINT;
  531. BEGIN
  532. (*TRACE(a,b);*)
  533. IF a = 0 THEN RETURN b
  534. ELSIF b = 0 THEN RETURN a
  535. ELSE RETURN SCM(a,b)
  536. END;
  537. END CommonAlignment;
  538. PROCEDURE Show*(context: Commands.Context);
  539. VAR
  540. fileName: Files.FileName; file: Files.File; reader: Files.Reader; writer: Streams.Writer;
  541. section: ObjectFile.Section; binary: BOOLEAN; poolMap, poolMapDummy: ObjectFile.PoolMap;
  542. offers, requires: ObjectFile.NameList;
  543. version: LONGINT;
  544. BEGIN
  545. IF context.arg.GetString(fileName) THEN
  546. file := Files.Old(fileName);
  547. IF file # NIL THEN
  548. NEW(reader,file,0);
  549. writer := Basic.GetWriter(Basic.GetDebugWriter(fileName));
  550. version := ReadHeader(reader, binary, poolMap, offers, requires);
  551. WriteHeader(writer, FALSE, NIL, poolMapDummy, offers, requires, NIL);
  552. WHILE reader.Peek () # 0X DO
  553. ObjectFile.ReadSection (reader, version, section,binary, poolMap);
  554. ObjectFile.WriteSection(writer, section, FALSE, NIL); (* textual *)
  555. reader.SkipWhitespace;
  556. END;
  557. writer.Update;
  558. ELSE
  559. context.error.String("file not found "); context.error.String(fileName); context.error.Ln
  560. END;
  561. ELSE
  562. context.error.String("no file specificed"); context.error.Ln
  563. END;
  564. END Show;
  565. PROCEDURE MakeLibrary*(context: Commands.Context);
  566. VAR
  567. fileName: Files.FileName; file: Files.File; reader: Files.Reader; (*writer: Streams.Writer;*)
  568. binary: BOOLEAN; poolMap, poolMapDummy: ObjectFile.PoolMap;
  569. bs: BinaryCode.Section;
  570. is: IntermediateCode.Section;
  571. sectionList: Sections.SectionList;
  572. section: ObjectFile.Section;
  573. i: LONGINT;
  574. dest: Files.FileName;
  575. writer: Files.Writer;
  576. name: ObjectFile.SegmentedName;
  577. version: LONGINT;
  578. offers, requires: ObjectFile.NameList;
  579. BEGIN
  580. NEW(sectionList);
  581. IF context.arg.GetString(dest) THEN
  582. (*writer := Basic.GetWriter(Basic.GetDebugWriter(fileName));*)
  583. WHILE context.arg.GetString(fileName) DO
  584. file := Files.Old(fileName);
  585. IF file # NIL THEN
  586. NEW(reader,file,0);
  587. version := ReadHeader(reader, binary, poolMap,offers, requires);
  588. WHILE reader.Peek () # 0X DO
  589. ObjectFile.InitSection(section);
  590. ObjectFile.ReadSection (reader, version, section, binary, poolMap);
  591. NEW(bs, SHORTINT(section.type) ,section.unit,name, FALSE, FALSE);
  592. bs.os := section;
  593. NEW(is, SHORTINT(bs.os.type), bs.os.identifier.name,NIL, FALSE);
  594. is.SetResolved(bs);
  595. sectionList.AddSection(is);
  596. reader.SkipWhitespace;
  597. END;
  598. ELSE
  599. context.error.String("file not found "); context.error.String(fileName); context.error.Ln;
  600. RETURN;
  601. END;
  602. END;
  603. file := Files.New(dest);
  604. Files.OpenWriter(writer, file, 0);
  605. WriteHeader(writer, TRUE, sectionList, poolMapDummy, NIL, NIL, NIL);
  606. FOR i := 0 TO sectionList.Length()-1 DO
  607. is := sectionList.GetSection(i)(IntermediateCode.Section);
  608. ObjectFile.WriteSection(writer, is.resolved.os, TRUE, poolMapDummy); (* binary *)
  609. END;
  610. writer.Update;
  611. Files.Register(file);
  612. context.out.String("Created library "); context.out.String(dest); context.out.Ln;
  613. END;
  614. END MakeLibrary;
  615. PROCEDURE Statistics*;
  616. VAR iterator: Basic.IntIterator; stat: SectionStat; index: StringPool.Index; any: ANY;
  617. BEGIN
  618. IF DetailedStatistics THEN
  619. iterator := statPool.GetIterator();
  620. WHILE iterator.GetNext(index, any) DO
  621. stat := any(SectionStat);
  622. TRACE(stat.name, stat.entries, stat.size);
  623. END;
  624. END;
  625. TRACE(statModules, statModulesSize);
  626. TRACE(statHeaders, statHeadersSize);
  627. ObjectFile.Statistics;
  628. END Statistics;
  629. PROCEDURE ResetStatistics*;
  630. BEGIN
  631. ObjectFile.ResetStatistics;
  632. statModules := 0; statModulesSize := 0;
  633. statHeaders := 0; statHeadersSize := 0;
  634. IF DetailedStatistics THEN
  635. NEW(statPool,64);
  636. END;
  637. END ResetStatistics;
  638. BEGIN
  639. ResetStatistics
  640. END FoxGenericObjectFile.