FoxSections.Mod 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. MODULE FoxSections; (** AUTHOR "fof"; PURPOSE "support for code sections and references"; *)
  2. IMPORT SyntaxTree := FoxSyntaxTree,Streams,Global := FoxGlobal,Formats := FoxFormats, Basic := FoxBasic, Strings, ObjectFile;
  3. CONST
  4. (* section categories *)
  5. EntryCodeSection*=ObjectFile.EntryCode;
  6. ExitCodeSection*=ObjectFile.ExitCode;
  7. InitCodeSection*=ObjectFile.InitCode;
  8. BodyCodeSection*=ObjectFile.BodyCode;
  9. CodeSection*=ObjectFile.Code;
  10. VarSection*=ObjectFile.Data;
  11. ConstSection*=ObjectFile.Const;
  12. InlineCodeSection*=10;
  13. UnknownSectionType*= 11;
  14. LineCommentStart*="; ";
  15. (* gensam *)
  16. UnknownSize* = -1;
  17. UndefinedFinalPosition* = -1;
  18. TYPE
  19. Identifier*=ObjectFile.Identifier;
  20. SectionName*= ObjectFile.SegmentedName;
  21. Section*=OBJECT
  22. VAR
  23. name-: SectionName; (* name of this section (globally unique-name derived from symbol name) *)
  24. type-: SHORTINT; (* CodeSection, InlineCodeSection, ... *)
  25. fixed-: BOOLEAN; (* whether the position of the section is fixed, as opposed to being restricted by an alignment *)
  26. positionOrAlignment-: LONGINT; (* the alignment OR the position *)
  27. fingerprint-: LONGINT; (* fingerprint of the corresponding syntax tree node *)
  28. bitsPerUnit-: LONGINT; (* the unit size given in bits *)
  29. (* for compatibility with old object file format *)
  30. symbol-: SyntaxTree.Symbol; (* corresponding symbol in AST *)
  31. offset-: LONGINT;
  32. isCaseTable*: BOOLEAN; (* necessary because old object file format cannot patch fixups in variable/constant area *)
  33. referenced-: BOOLEAN;
  34. (* for linking *)
  35. isReachable-: BOOLEAN;
  36. PROCEDURE & InitSection*(type: SHORTINT; CONST n: ObjectFile.SegmentedName; symbol: SyntaxTree.Symbol);
  37. BEGIN
  38. name := n;
  39. SELF.symbol := symbol;
  40. SELF.type := type;
  41. offset := 0;
  42. referenced := TRUE;
  43. fixed := FALSE;
  44. positionOrAlignment := 1;
  45. fingerprint := 0;
  46. bitsPerUnit := UnknownSize;
  47. isCaseTable := FALSE;
  48. END InitSection;
  49. PROCEDURE IsCode*(): BOOLEAN;
  50. BEGIN
  51. RETURN type IN {CodeSection, InitCodeSection, BodyCodeSection};
  52. END IsCode;
  53. PROCEDURE SetReferenced*(ref: BOOLEAN);
  54. BEGIN referenced := ref;
  55. END SetReferenced;
  56. PROCEDURE SetOffset*(offset: LONGINT);
  57. BEGIN SELF.offset := offset;
  58. END SetOffset;
  59. PROCEDURE SetReachability*(isReachable: BOOLEAN);
  60. BEGIN SELF.isReachable := isReachable
  61. END SetReachability;
  62. PROCEDURE SetBitsPerUnit*(bitsPerUnit: LONGINT);
  63. BEGIN SELF.bitsPerUnit := bitsPerUnit
  64. END SetBitsPerUnit;
  65. PROCEDURE IsAligned*(): BOOLEAN;
  66. BEGIN RETURN ~fixed & (positionOrAlignment > 1)
  67. END IsAligned;
  68. PROCEDURE SetPositionOrAlignment*(isFixed: BOOLEAN; positionOrAlignment: LONGINT);
  69. BEGIN
  70. SELF.fixed := isFixed;
  71. SELF.positionOrAlignment := positionOrAlignment
  72. END SetPositionOrAlignment;
  73. PROCEDURE GetSize*(): LONGINT;
  74. BEGIN RETURN UnknownSize
  75. END GetSize;
  76. PROCEDURE SetFingerprint*(fingerprint: LONGINT);
  77. BEGIN SELF.fingerprint := fingerprint
  78. END SetFingerprint;
  79. (** change the type of a section **)
  80. PROCEDURE SetType*(type: SHORTINT);
  81. BEGIN SELF.type := type
  82. END SetType;
  83. PROCEDURE Dump*(w: Streams.Writer);
  84. BEGIN
  85. w.String(".");
  86. CASE type OF
  87. | EntryCodeSection: w.String("entrycode")
  88. | ExitCodeSection: w.String("exitcode")
  89. | CodeSection: w.String("code")
  90. | BodyCodeSection: w.String("bodycode")
  91. | InlineCodeSection: w.String("inlinecode")
  92. | VarSection: w.String("var");
  93. | ConstSection: w.String("const");
  94. | InitCodeSection: w.String("initcode");
  95. ELSE
  96. w.String("UNDEFINED")
  97. END;
  98. w.String(" ");
  99. DumpName(w);
  100. (* positional restrictions *)
  101. IF fixed THEN
  102. w.String(" fixed="); w.Int(positionOrAlignment, 0)
  103. ELSIF positionOrAlignment > 1 THEN
  104. w.String(" aligned="); w.Int(positionOrAlignment, 0)
  105. END;
  106. IF fingerprint # 0 THEN w.String(" fingerprint="); w.Hex(fingerprint, -8) END;
  107. IF bitsPerUnit # UnknownSize THEN w.String(" unit="); w.Int(bitsPerUnit, 0) END;
  108. (* note: this information is actually redundant *)
  109. IF GetSize() # UnknownSize THEN w.String(" size="); w.Int(GetSize(), 0) END;
  110. w.Update
  111. END Dump;
  112. PROCEDURE WriteRaw*(w: Streams.Writer);
  113. BEGIN
  114. w.RawInt(type);
  115. Basic.WriteSegmentedName(w,name);
  116. w.RawBool(fixed);
  117. w.RawLInt(positionOrAlignment);
  118. w.RawLInt(fingerprint);
  119. w.RawLInt(bitsPerUnit);
  120. END WriteRaw;
  121. PROCEDURE DumpName*(w: Streams.Writer);
  122. BEGIN
  123. Basic.WriteSegmentedName(w,name);
  124. END DumpName;
  125. END Section;
  126. CommentStr* = POINTER TO ARRAY OF CHAR;
  127. Comment* = OBJECT
  128. VAR str-: CommentStr; strLen: LONGINT; pos-: LONGINT; nextComment-: Comment;
  129. PROCEDURE &Init*(pos: LONGINT);
  130. BEGIN
  131. SELF.pos := pos;
  132. NEW(str,32); strLen := 0;
  133. str[0] := 0X;
  134. END Init;
  135. PROCEDURE Append(CONST buf: ARRAY OF CHAR; ofs, len: LONGINT);
  136. PROCEDURE Resize(newLen: LONGINT);
  137. VAR new: CommentStr; i: LONGINT;
  138. BEGIN
  139. NEW(new,newLen);
  140. FOR i := 0 TO strLen-1 DO
  141. new[i] := str[i]
  142. END;
  143. str := new
  144. END Resize;
  145. BEGIN
  146. INC(len,ofs);
  147. ASSERT(LEN(buf) >= len);
  148. WHILE (ofs < len) & (buf[ofs] # 0X) DO
  149. IF LEN(str) <= strLen THEN Resize(2*strLen) END;
  150. str[strLen] := buf[ofs];
  151. INC(ofs); INC(strLen);
  152. END;
  153. IF LEN(str) <= strLen THEN Resize(2*strLen) END;
  154. str[strLen] := 0X;
  155. END Append;
  156. PROCEDURE Dump*(w: Streams.Writer);
  157. VAR i: LONGINT;ch: CHAR; newln: BOOLEAN;
  158. BEGIN
  159. IF w IS Basic.Writer THEN w(Basic.Writer).BeginComment; w(Basic.Writer).IncIndent; END;
  160. w.String("; ");
  161. i := 0; ch := str[i]; newln := FALSE;
  162. WHILE(ch#0X) DO
  163. IF (ch = 0DX) OR (ch = 0AX) THEN newln := TRUE
  164. ELSE
  165. IF newln THEN w.Ln; w.String(LineCommentStart); newln := FALSE; END;
  166. w.Char(ch);
  167. END;
  168. INC(i); ch := str[i];
  169. END;
  170. IF w IS Basic.Writer THEN w(Basic.Writer).EndComment; w(Basic.Writer).DecIndent;END;
  171. (*w.Update;*)
  172. END Dump;
  173. END Comment;
  174. GetPCProcedure=PROCEDURE{DELEGATE}(): LONGINT;
  175. CommentWriter*= OBJECT (Streams.Writer)
  176. VAR
  177. firstComment-,lastComment-: Comment; comments-: LONGINT;
  178. getPC: GetPCProcedure;
  179. PROCEDURE AppendToLine*( CONST buf: ARRAY OF CHAR; ofs, len: LONGINT; propagate: BOOLEAN; VAR res: LONGINT );
  180. VAR pos: LONGINT;
  181. BEGIN
  182. IF len = 0 THEN RETURN END;
  183. pos := getPC();
  184. IF lastComment = NIL THEN
  185. NEW(lastComment,pos); firstComment := lastComment;
  186. ELSIF (lastComment.pos # pos) THEN
  187. NEW(lastComment.nextComment,pos);
  188. lastComment := lastComment.nextComment;
  189. END;
  190. lastComment.Append(buf,ofs,len)
  191. END AppendToLine;
  192. PROCEDURE Ln*;
  193. BEGIN
  194. Ln^;
  195. (*Update;*)
  196. END Ln;
  197. PROCEDURE Reset*;
  198. BEGIN
  199. firstComment := NIL; lastComment := NIL; comments := 0;
  200. Reset^;
  201. END Reset;
  202. PROCEDURE & InitCommentWriter*(getPC: GetPCProcedure);
  203. BEGIN
  204. SELF.getPC := getPC;
  205. InitWriter(AppendToLine,256);
  206. firstComment := NIL; lastComment := NIL; comments := 0;
  207. END InitCommentWriter;
  208. END CommentWriter;
  209. SectionLookup = OBJECT(Basic.HashTable); (* SyntaxTree.Symbol _> Symbol *)
  210. VAR
  211. PROCEDURE GetSection(symbol: SyntaxTree.Symbol):Section;
  212. VAR p: ANY;
  213. BEGIN
  214. p := Get(symbol);
  215. IF p # NIL THEN
  216. ASSERT(p(Section).symbol = symbol);
  217. RETURN p(Section);
  218. ELSE
  219. RETURN NIL
  220. END;
  221. END GetSection;
  222. PROCEDURE PutSection(symbol: SyntaxTree.Symbol; section: Section);
  223. BEGIN
  224. Put(symbol,section);
  225. END PutSection;
  226. END SectionLookup;
  227. SectionNameLookup = OBJECT(Basic.HashTableSegmentedName); (* SyntaxTree.Symbol _> Symbol *)
  228. PROCEDURE GetSection(CONST name: Basic.SegmentedName):Section;
  229. VAR p: ANY;
  230. BEGIN
  231. p := Get(name);
  232. IF p # NIL THEN RETURN p(Section) ELSE RETURN NIL END;
  233. END GetSection;
  234. PROCEDURE PutSection(CONST name:Basic.SegmentedName; section: Section);
  235. BEGIN
  236. Put(name, section);
  237. END PutSection;
  238. END SectionNameLookup;
  239. (** a list of sections
  240. note: a section may be part of multiple lists in this implementation
  241. **)
  242. SectionList* = OBJECT(Basic.List)
  243. VAR
  244. lookup: SectionLookup;
  245. lookupName: SectionNameLookup;
  246. PROCEDURE & InitListOfSections*;
  247. BEGIN
  248. NEW(lookup, 128);
  249. NEW(lookupName, 128);
  250. InitList(128) (* initializer of general list *)
  251. END InitListOfSections;
  252. PROCEDURE GetSection*(index: LONGINT): Section;
  253. VAR
  254. any: ANY;
  255. BEGIN
  256. any := Get(index);
  257. RETURN any(Section)
  258. END GetSection;
  259. PROCEDURE SetSection*(index: LONGINT; section: Section);
  260. BEGIN
  261. Set(index, section)
  262. END SetSection;
  263. (* note: this procedure cannot be called "Add" as it was the case in the old section list implementation *)
  264. PROCEDURE AddSection*(section: Section);
  265. BEGIN
  266. (* assert that the section is not already present *)
  267. ASSERT((FindBySymbol(section.symbol) = NIL) & (FindByName(section.name) = NIL));
  268. IF section.symbol # NIL THEN (* special case, may not be added to lookup list *)
  269. lookup.PutSection(section.symbol, section)
  270. END;
  271. IF section.name[0] >= 0 THEN
  272. lookupName.PutSection(section.name, section);
  273. END;
  274. Add(section)
  275. END AddSection;
  276. (** finds a section with a certain AST symbol **)
  277. PROCEDURE FindBySymbol*(CONST symbol: SyntaxTree.Symbol): Section;
  278. BEGIN
  279. IF symbol = NIL THEN
  280. RETURN NIL
  281. ELSE
  282. RETURN lookup.GetSection(symbol)
  283. END
  284. END FindBySymbol;
  285. (** finds a section with a certain name **)
  286. PROCEDURE FindByName*(CONST name: Basic.SegmentedName): Section;
  287. BEGIN
  288. RETURN lookupName.GetSection(name)
  289. END FindByName;
  290. PROCEDURE Dump*(w: Streams.Writer);
  291. VAR
  292. i: LONGINT;
  293. section: Section;
  294. BEGIN
  295. FOR i := 0 TO Length() - 1 DO
  296. section := GetSection(i);
  297. section.Dump(w); w.Ln
  298. END;
  299. END Dump;
  300. PROCEDURE WriteRaw*(w: Streams.Writer);
  301. VAR
  302. i: LONGINT;
  303. section: Section;
  304. BEGIN
  305. FOR i := 0 TO Length() - 1 DO
  306. section := GetSection(i);
  307. section.WriteRaw(w);
  308. END;
  309. END WriteRaw;
  310. END SectionList;
  311. NameEntry = POINTER TO RECORD
  312. name: SyntaxTree.IdentifierString;
  313. END;
  314. (* TODO: efficient implementation using hash table *)
  315. NameList* = OBJECT(Basic.List)
  316. PROCEDURE AddName*(CONST moduleName: ARRAY OF CHAR);
  317. VAR entry: NameEntry;
  318. BEGIN
  319. NEW(entry);
  320. COPY(moduleName, entry.name);
  321. Add(entry)
  322. END AddName;
  323. PROCEDURE GetName*(index: LONGINT): SyntaxTree.IdentifierString;
  324. VAR any: ANY;
  325. BEGIN
  326. any := Get(index);
  327. ASSERT(any IS NameEntry);
  328. RETURN any(NameEntry).name
  329. END GetName;
  330. PROCEDURE ContainsName*(name: SyntaxTree.IdentifierString): BOOLEAN;
  331. VAR i: LONGINT;
  332. BEGIN
  333. FOR i := 0 TO Length() - 1 DO
  334. IF name = GetName(i) THEN RETURN TRUE END
  335. END;
  336. RETURN FALSE
  337. END ContainsName;
  338. END NameList;
  339. (** output of (intermediate) code generation **)
  340. Module* = OBJECT (Formats.GeneratedModule)
  341. VAR
  342. allSections-: SectionList;
  343. importedSections-: SectionList; (* necessary for binary object file format, for reference to symbol *)
  344. platformName-: SyntaxTree.IdentifierString;
  345. imports-: NameList;
  346. PROCEDURE & Init*(module: SyntaxTree.Module; system: Global.System);
  347. BEGIN
  348. Init^(module,system);
  349. NEW(allSections);
  350. NEW(importedSections);
  351. NEW(imports, 128);
  352. END Init;
  353. (*
  354. PROCEDURE SetSections*(sections: SectionList);
  355. BEGIN SELF.allSections := sections
  356. END SetSections;
  357. *)
  358. PROCEDURE SetImports*(imports: NameList);
  359. BEGIN SELF.imports := imports
  360. END SetImports;
  361. PROCEDURE SetPlatformName*(CONST platformName: ARRAY OF CHAR);
  362. BEGIN COPY(platformName, SELF.platformName)
  363. END SetPlatformName;
  364. PROCEDURE Dump*(w: Streams.Writer);
  365. VAR
  366. dump: Basic.Writer;
  367. name: SyntaxTree.IdentifierString;
  368. i: LONGINT;
  369. BEGIN
  370. dump := Basic.GetWriter(w);
  371. (* dump module directive *)
  372. dump.String(".module ");
  373. dump.String(moduleName); dump.Ln;
  374. dump.Ln;
  375. (* dump platform directive *)
  376. IF platformName # "" THEN
  377. dump.String(".platform ");
  378. dump.String(platformName); dump.Ln;
  379. dump.Ln
  380. END;
  381. (* dump imports directive *)
  382. IF imports.Length() > 0 THEN
  383. dump.String(".imports ");
  384. FOR i := 0 TO imports.Length() - 1 DO
  385. IF i # 0 THEN dump.String(", ") END;
  386. name := imports.GetName(i);
  387. IF name = "" THEN
  388. dump.String("<import failed>")
  389. ELSE
  390. dump.String(name)
  391. END
  392. END;
  393. dump.Ln; dump.Ln
  394. END;
  395. (* dump all sections *)
  396. allSections.Dump(w)
  397. END Dump;
  398. END Module;
  399. PROCEDURE DumpFiltered*(w: Streams.Writer; module: Module; CONST filter: ARRAY OF CHAR);
  400. VAR
  401. i: LONGINT;
  402. section: Section;
  403. name: ObjectFile.SectionName;
  404. BEGIN
  405. FOR i := 0 TO module.allSections.Length() - 1 DO
  406. section := module.allSections.GetSection(i);
  407. ObjectFile.SegmentedNameToString(section.name,name);
  408. IF Strings.Match(filter, name) THEN section.Dump(w); w.Ln; END
  409. END
  410. END DumpFiltered;
  411. PROCEDURE NewCommentWriter*(getPC: GetPCProcedure): CommentWriter;
  412. VAR c: CommentWriter;
  413. BEGIN
  414. NEW(c,getPC); RETURN c
  415. END NewCommentWriter;
  416. END FoxSections.