FoxGenericObjectFile.Mod 24 KB

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