FoxSections.Mod 12 KB

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