2
0

FoxSections.Mod 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  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 WriteRaw*(w: Streams.Writer);
  115. BEGIN
  116. w.RawInt(type);
  117. Basic.WriteSegmentedName(w,name);
  118. w.RawBool(fixed);
  119. w.RawLInt(positionOrAlignment);
  120. w.RawLInt(priority);
  121. w.RawLInt(fingerprint);
  122. w.RawLInt(bitsPerUnit);
  123. END WriteRaw;
  124. PROCEDURE DumpName*(w: Streams.Writer);
  125. BEGIN
  126. Basic.WriteSegmentedName(w,name);
  127. END DumpName;
  128. END Section;
  129. CommentStr* = POINTER TO ARRAY OF CHAR;
  130. Comment* = OBJECT
  131. VAR str-: CommentStr; strLen: LONGINT; pos-: LONGINT; nextComment-: Comment;
  132. PROCEDURE &Init*(pos: LONGINT);
  133. BEGIN
  134. SELF.pos := pos;
  135. NEW(str,32); strLen := 0;
  136. str[0] := 0X;
  137. END Init;
  138. PROCEDURE Append(CONST buf: ARRAY OF CHAR; ofs, len: LONGINT);
  139. PROCEDURE Resize(newLen: LONGINT);
  140. VAR new: CommentStr; i: LONGINT;
  141. BEGIN
  142. NEW(new,newLen);
  143. FOR i := 0 TO strLen-1 DO
  144. new[i] := str[i]
  145. END;
  146. str := new
  147. END Resize;
  148. BEGIN
  149. INC(len,ofs);
  150. ASSERT(LEN(buf) >= len);
  151. WHILE (ofs < len) & (buf[ofs] # 0X) DO
  152. IF LEN(str) <= strLen THEN Resize(2*strLen) END;
  153. str[strLen] := buf[ofs];
  154. INC(ofs); INC(strLen);
  155. END;
  156. IF LEN(str) <= strLen THEN Resize(2*strLen) END;
  157. str[strLen] := 0X;
  158. END Append;
  159. PROCEDURE Dump*(w: Streams.Writer);
  160. VAR i: LONGINT;ch: CHAR; newln: BOOLEAN;
  161. BEGIN
  162. IF w IS Basic.Writer THEN w(Basic.Writer).BeginComment; w(Basic.Writer).IncIndent; END;
  163. w.String("; ");
  164. i := 0; ch := str[i]; newln := FALSE;
  165. WHILE(ch#0X) DO
  166. IF (ch = 0DX) OR (ch = 0AX) THEN newln := TRUE
  167. ELSE
  168. IF newln THEN w.Ln; w.String(LineCommentStart); newln := FALSE; END;
  169. w.Char(ch);
  170. END;
  171. INC(i); ch := str[i];
  172. END;
  173. IF w IS Basic.Writer THEN w(Basic.Writer).EndComment; w(Basic.Writer).DecIndent;END;
  174. (*w.Update;*)
  175. END Dump;
  176. END Comment;
  177. GetPCProcedure=PROCEDURE{DELEGATE}(): LONGINT;
  178. CommentWriter*= OBJECT (Streams.Writer)
  179. VAR
  180. firstComment-,lastComment-: Comment; comments-: LONGINT;
  181. getPC: GetPCProcedure;
  182. PROCEDURE AppendToLine*( CONST buf: ARRAY OF CHAR; ofs, len: LONGINT; propagate: BOOLEAN; VAR res: LONGINT );
  183. VAR pos: LONGINT;
  184. BEGIN
  185. IF len = 0 THEN RETURN END;
  186. pos := getPC();
  187. IF lastComment = NIL THEN
  188. NEW(lastComment,pos); firstComment := lastComment;
  189. ELSIF (lastComment.pos # pos) THEN
  190. NEW(lastComment.nextComment,pos);
  191. lastComment := lastComment.nextComment;
  192. END;
  193. lastComment.Append(buf,ofs,len)
  194. END AppendToLine;
  195. PROCEDURE Ln;
  196. BEGIN
  197. Ln^;
  198. (*Update;*)
  199. END Ln;
  200. PROCEDURE Reset*;
  201. BEGIN
  202. firstComment := NIL; lastComment := NIL; comments := 0;
  203. Reset^;
  204. END Reset;
  205. PROCEDURE & InitCommentWriter*(getPC: GetPCProcedure);
  206. BEGIN
  207. SELF.getPC := getPC;
  208. InitWriter(AppendToLine,256);
  209. firstComment := NIL; lastComment := NIL; comments := 0;
  210. END InitCommentWriter;
  211. END CommentWriter;
  212. SectionLookup = OBJECT(Basic.HashTable); (* SyntaxTree.Symbol _> Symbol *)
  213. VAR
  214. PROCEDURE GetSection(symbol: SyntaxTree.Symbol):Section;
  215. VAR p: ANY;
  216. BEGIN
  217. p := Get(symbol);
  218. IF p # NIL THEN
  219. ASSERT(p(Section).symbol = symbol);
  220. RETURN p(Section);
  221. ELSE
  222. RETURN NIL
  223. END;
  224. END GetSection;
  225. PROCEDURE PutSection(symbol: SyntaxTree.Symbol; section: Section);
  226. BEGIN
  227. Put(symbol,section);
  228. END PutSection;
  229. END SectionLookup;
  230. SectionNameLookup = OBJECT(Basic.HashTableSegmentedName); (* SyntaxTree.Symbol _> Symbol *)
  231. PROCEDURE GetSection(CONST name: Basic.SegmentedName):Section;
  232. VAR p: ANY;
  233. BEGIN
  234. p := Get(name);
  235. IF p # NIL THEN RETURN p(Section) ELSE RETURN NIL END;
  236. END GetSection;
  237. PROCEDURE PutSection(CONST name:Basic.SegmentedName; section: Section);
  238. BEGIN
  239. Put(name, section);
  240. END PutSection;
  241. END SectionNameLookup;
  242. (** a list of sections
  243. note: a section may be part of multiple lists in this implementation
  244. **)
  245. SectionList* = OBJECT(Basic.List)
  246. VAR
  247. lookup: SectionLookup;
  248. lookupName: SectionNameLookup;
  249. PROCEDURE & InitListOfSections*;
  250. BEGIN
  251. NEW(lookup, 128);
  252. NEW(lookupName, 128);
  253. InitList(128) (* initializer of general list *)
  254. END InitListOfSections;
  255. PROCEDURE GetSection*(index: LONGINT): Section;
  256. VAR
  257. any: ANY;
  258. BEGIN
  259. any := Get(index);
  260. RETURN any(Section)
  261. END GetSection;
  262. PROCEDURE SetSection*(index: LONGINT; section: Section);
  263. BEGIN
  264. Set(index, section)
  265. END SetSection;
  266. (* note: this procedure cannot be called "Add" as it was the case in the old section list implementation *)
  267. PROCEDURE AddSection*(section: Section);
  268. BEGIN
  269. (* assert that the section is not already present *)
  270. ASSERT((FindBySymbol(section.symbol) = NIL) & (FindByName(section.name) = NIL));
  271. IF section.symbol # NIL THEN (* special case, may not be added to lookup list *)
  272. lookup.PutSection(section.symbol, section)
  273. END;
  274. IF section.name[0] >= 0 THEN
  275. lookupName.PutSection(section.name, section);
  276. END;
  277. Add(section)
  278. END AddSection;
  279. (** finds a section with a certain AST symbol **)
  280. PROCEDURE FindBySymbol*(CONST symbol: SyntaxTree.Symbol): Section;
  281. BEGIN
  282. IF symbol = NIL THEN
  283. RETURN NIL
  284. ELSE
  285. RETURN lookup.GetSection(symbol)
  286. END
  287. END FindBySymbol;
  288. (** finds a section with a certain name **)
  289. PROCEDURE FindByName*(CONST name: Basic.SegmentedName): Section;
  290. BEGIN
  291. RETURN lookupName.GetSection(name)
  292. END FindByName;
  293. PROCEDURE Dump*(w: Streams.Writer);
  294. VAR
  295. i: LONGINT;
  296. section: Section;
  297. BEGIN
  298. FOR i := 0 TO Length() - 1 DO
  299. section := GetSection(i);
  300. section.Dump(w); w.Ln
  301. END;
  302. END Dump;
  303. PROCEDURE WriteRaw*(w: Streams.Writer);
  304. VAR
  305. i: LONGINT;
  306. section: Section;
  307. BEGIN
  308. FOR i := 0 TO Length() - 1 DO
  309. section := GetSection(i);
  310. section.WriteRaw(w);
  311. END;
  312. END WriteRaw;
  313. END SectionList;
  314. NameEntry = POINTER TO RECORD
  315. name: SyntaxTree.IdentifierString;
  316. END;
  317. (* TODO: efficient implementation using hash table *)
  318. NameList* = OBJECT(Basic.List)
  319. PROCEDURE AddName*(CONST moduleName: ARRAY OF CHAR);
  320. VAR entry: NameEntry;
  321. BEGIN
  322. NEW(entry);
  323. COPY(moduleName, entry.name);
  324. Add(entry)
  325. END AddName;
  326. PROCEDURE GetName*(index: LONGINT): SyntaxTree.IdentifierString;
  327. VAR any: ANY;
  328. BEGIN
  329. any := Get(index);
  330. ASSERT(any IS NameEntry);
  331. RETURN any(NameEntry).name
  332. END GetName;
  333. PROCEDURE ContainsName*(name: SyntaxTree.IdentifierString): BOOLEAN;
  334. VAR i: LONGINT;
  335. BEGIN
  336. FOR i := 0 TO Length() - 1 DO
  337. IF name = GetName(i) THEN RETURN TRUE END
  338. END;
  339. RETURN FALSE
  340. END ContainsName;
  341. END NameList;
  342. (** output of (intermediate) code generation **)
  343. Module* = OBJECT (Formats.GeneratedModule)
  344. VAR
  345. allSections-: SectionList;
  346. importedSections-: SectionList; (* necessary for binary object file format, for reference to symbol *)
  347. platformName-: SyntaxTree.IdentifierString;
  348. imports-: NameList;
  349. PROCEDURE & Init*(module: SyntaxTree.Module; system: Global.System);
  350. BEGIN
  351. Init^(module,system);
  352. NEW(allSections);
  353. NEW(importedSections);
  354. NEW(imports, 128);
  355. END Init;
  356. (*
  357. PROCEDURE SetSections*(sections: SectionList);
  358. BEGIN SELF.allSections := sections
  359. END SetSections;
  360. *)
  361. PROCEDURE SetImports*(imports: NameList);
  362. BEGIN SELF.imports := imports
  363. END SetImports;
  364. PROCEDURE SetPlatformName*(CONST platformName: ARRAY OF CHAR);
  365. BEGIN COPY(platformName, SELF.platformName)
  366. END SetPlatformName;
  367. PROCEDURE Dump*(w: Streams.Writer);
  368. VAR
  369. dump: Basic.Writer;
  370. name: SyntaxTree.IdentifierString;
  371. i: LONGINT;
  372. BEGIN
  373. dump := Basic.GetWriter(w);
  374. (* dump module directive *)
  375. dump.String(".module ");
  376. dump.String(moduleName); dump.Ln;
  377. dump.Ln;
  378. (* dump platform directive *)
  379. IF platformName # "" THEN
  380. dump.String(".platform ");
  381. dump.String(platformName); dump.Ln;
  382. dump.Ln
  383. END;
  384. (* dump imports directive *)
  385. IF imports.Length() > 0 THEN
  386. dump.String(".imports ");
  387. FOR i := 0 TO imports.Length() - 1 DO
  388. IF i # 0 THEN dump.String(", ") END;
  389. name := imports.GetName(i);
  390. IF name = "" THEN
  391. dump.String("<import failed>")
  392. ELSE
  393. dump.String(name)
  394. END
  395. END;
  396. dump.Ln; dump.Ln
  397. END;
  398. (* dump all sections *)
  399. allSections.Dump(w)
  400. END Dump;
  401. END Module;
  402. PROCEDURE DumpFiltered*(w: Streams.Writer; module: Module; CONST filter: ARRAY OF CHAR);
  403. VAR
  404. i: LONGINT;
  405. section: Section;
  406. name: ObjectFile.SectionName;
  407. BEGIN
  408. FOR i := 0 TO module.allSections.Length() - 1 DO
  409. section := module.allSections.GetSection(i);
  410. ObjectFile.SegmentedNameToString(section.name,name);
  411. IF Strings.Match(filter, name) THEN section.Dump(w); w.Ln; END
  412. END
  413. END DumpFiltered;
  414. PROCEDURE NewCommentWriter*(getPC: GetPCProcedure): CommentWriter;
  415. VAR c: CommentWriter;
  416. BEGIN
  417. NEW(c,getPC); RETURN c
  418. END NewCommentWriter;
  419. END FoxSections.