omfbase.pas 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. {
  2. Copyright (c) 2015 by Nikolay Nikolov
  3. Contains Relocatable Object Module Format (OMF) definitions
  4. This is the object format used on the i8086-msdos platform.
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit omfbase;
  19. {$i fpcdefs.inc}
  20. interface
  21. {$H+}
  22. uses
  23. owbase;
  24. const
  25. { OMF record types }
  26. RT_THEADR = $80; { Translator Header Record }
  27. RT_LHEADR = $82; { Library Module Header Record }
  28. RT_COMENT = $88; { Comment Record }
  29. RT_MODEND = $8A; { Module End Record }
  30. RT_MODEND32 = $8B;
  31. RT_EXTDEF = $8C; { External Names Definition Record }
  32. RT_PUBDEF = $90; { Public Names Definition Record }
  33. RT_PUBDEF32 = $91;
  34. RT_LINNUM = $94; { Line Numbers Record }
  35. RT_LINNUM32 = $95;
  36. RT_LNAMES = $96; { List of Names Record }
  37. RT_SEGDEF = $98; { Segment Definition Record }
  38. RT_SEGDEF32 = $99;
  39. RT_GRPDEF = $9A; { Group Definition Record }
  40. RT_FIXUPP = $9C; { Fixup Record }
  41. RT_FIXUPP32 = $9D;
  42. RT_LEDATA = $A0; { Logical Enumerated Data Record }
  43. RT_LEDATA32 = $A1;
  44. RT_LIDATA = $A2; { Logical Iterated Data Record }
  45. RT_LIDATA32 = $A3;
  46. RT_COMDEF = $B0; { Communal Names Definition Record }
  47. RT_BAKPAT = $B2; { Backpatch Record }
  48. RT_BAKPAT32 = $B3;
  49. RT_LEXTDEF = $B4; { Local External Names Definition Record }
  50. RT_LEXTDEF32 = $B5;
  51. RT_LPUBDEF = $B6; { Local Public Names Definition Record }
  52. RT_LPUBDEF32 = $B7;
  53. RT_LCOMDEF = $B8; { Local Communal Names Definition Record }
  54. RT_CEXTDEF = $BC; { COMDAT External Names Definition Record }
  55. RT_COMDAT = $C2; { Initialized Communal Data Record }
  56. RT_COMDAT32 = $C3;
  57. RT_LINSYM = $C4; { Symbol Line Numbers Record }
  58. RT_LINSYM32 = $C5;
  59. RT_ALIAS = $C6; { Alias Definition Record }
  60. RT_NBKPAT = $C8; { Named Backpatch Record }
  61. RT_NBKPAT32 = $C9;
  62. RT_LLNAMES = $CA; { Local Logical Names Definition Record }
  63. RT_VERNUM = $CC; { OMF Version Number Record }
  64. RT_VENDEXT = $CE; { Vendor-specific OMF Extension Record }
  65. { OMF comment class }
  66. CC_Translator = $00; { language translator (compiler or assembler) name }
  67. CC_IntelCopyright = $01;
  68. CC_IntelReservedRangeStart = $02;
  69. CC_IntelReservedRangeEnd = $9B;
  70. CC_LibrarySpecifierObsolete = $81;
  71. CC_MsDosVersionObsolete = $9C;
  72. CC_MemoryModel = $9D;
  73. CC_DOSSEG = $9E;
  74. CC_DefaultLibrarySearchName = $9F;
  75. CC_OmfExtension = $A0;
  76. CC_NewOmfExtension = $A1;
  77. CC_LinkPassSeparator = $A2;
  78. CC_LIBMOD = $A3;
  79. CC_EXESTR = $A4;
  80. CC_INCERR = $A6;
  81. CC_NOPAD = $A7;
  82. CC_WKEXT = $A8;
  83. CC_LZEXT = $A9;
  84. CC_Comment = $DA;
  85. CC_Compiler = $DB;
  86. CC_Date = $DC;
  87. CC_Timestamp = $DD;
  88. CC_User = $DF;
  89. CC_DependencyFileBorland = $E9;
  90. CC_CommandLineMicrosoft = $FF;
  91. type
  92. { TOmfRawRecord }
  93. TOmfRawRecord = class
  94. private
  95. function GetChecksumByte: Byte;
  96. function GetRecordLength: Word;
  97. function GetRecordType: Byte;
  98. procedure SetChecksumByte(AValue: Byte);
  99. procedure SetRecordLength(AValue: Word);
  100. procedure SetRecordType(AValue: Byte);
  101. public
  102. RawData: array [-3..65535] of Byte;
  103. property RecordType: Byte read GetRecordType write SetRecordType;
  104. property RecordLength: Word read GetRecordLength write SetRecordLength;
  105. function ReadStringAt(Offset: Integer; out s: string): Integer;
  106. function WriteStringAt(Offset: Integer; s: string): Integer;
  107. procedure CalculateChecksumByte;
  108. function VerifyChecksumByte: boolean;
  109. property ChecksumByte: Byte read GetChecksumByte write SetChecksumByte;
  110. procedure ReadFrom(aReader: TObjectReader);
  111. procedure WriteTo(aWriter: TObjectWriter);
  112. end;
  113. { TOmfParsedRecord }
  114. TOmfParsedRecord = class
  115. public
  116. procedure DecodeFrom(RawRecord: TOmfRawRecord);virtual;abstract;
  117. procedure EncodeTo(RawRecord: TOmfRawRecord);virtual;abstract;
  118. end;
  119. { TOmfRecord_THEADR }
  120. TOmfRecord_THEADR = class(TOmfParsedRecord)
  121. private
  122. FModuleName: string;
  123. public
  124. procedure DecodeFrom(RawRecord: TOmfRawRecord);override;
  125. procedure EncodeTo(RawRecord: TOmfRawRecord);override;
  126. property ModuleName: string read FModuleName write FModuleName;
  127. end;
  128. { TOmfRecord_COMENT }
  129. TOmfRecord_COMENT = class(TOmfParsedRecord)
  130. private
  131. FCommentType: Byte;
  132. FCommentClass: Byte;
  133. FCommentString: string;
  134. function GetNoList: Boolean;
  135. function GetNoPurge: Boolean;
  136. procedure SetNoList(AValue: Boolean);
  137. procedure SetNoPurge(AValue: Boolean);
  138. public
  139. procedure DecodeFrom(RawRecord: TOmfRawRecord);override;
  140. procedure EncodeTo(RawRecord: TOmfRawRecord);override;
  141. property CommentType: Byte read FCommentType write FCommentType;
  142. property CommentClass: Byte read FCommentClass write FCommentClass;
  143. property CommentString: string read FCommentString write FCommentString;
  144. property NoPurge: Boolean read GetNoPurge write SetNoPurge;
  145. property NoList: Boolean read GetNoList write SetNoList;
  146. end;
  147. implementation
  148. uses
  149. verbose;
  150. { TOmfRawRecord }
  151. function TOmfRawRecord.GetRecordType: Byte;
  152. begin
  153. Result:=RawData[-3];
  154. end;
  155. procedure TOmfRawRecord.SetRecordType(AValue: Byte);
  156. begin
  157. RawData[-3]:=AValue;
  158. end;
  159. function TOmfRawRecord.GetRecordLength: Word;
  160. begin
  161. Result:=RawData[-2] or (RawData[-1] shl 8);
  162. end;
  163. procedure TOmfRawRecord.SetRecordLength(AValue: Word);
  164. begin
  165. RawData[-2]:=Byte(AValue);
  166. RawData[-1]:=Byte(AValue shr 8);
  167. end;
  168. function TOmfRawRecord.ReadStringAt(Offset: Integer; out s: string): Integer;
  169. var
  170. len: Byte;
  171. begin
  172. len:=RawData[Offset];
  173. Result:=Offset+len+1;
  174. if result>RecordLength then
  175. internalerror(2015033103);
  176. SetLength(s, len);
  177. UniqueString(s);
  178. Move(RawData[Offset+1],s[1],len);
  179. end;
  180. function TOmfRawRecord.WriteStringAt(Offset: Integer; s: string): Integer;
  181. begin
  182. if Length(s)>255 then
  183. internalerror(2015033101);
  184. result:=Offset+Length(s)+1;
  185. if result>High(RawData) then
  186. internalerror(2015033102);
  187. RawData[Offset]:=Length(s);
  188. Move(s[1], RawData[Offset+1], Length(s));
  189. end;
  190. function TOmfRawRecord.GetChecksumByte: Byte;
  191. begin
  192. if RecordLength>0 then
  193. Result:=RawData[RecordLength-1]
  194. else
  195. Result:=0;
  196. end;
  197. procedure TOmfRawRecord.SetChecksumByte(AValue: Byte);
  198. begin
  199. if RecordLength>0 then
  200. RawData[RecordLength-1]:=AValue;
  201. end;
  202. procedure TOmfRawRecord.CalculateChecksumByte;
  203. var
  204. I: Integer;
  205. b: Byte;
  206. begin
  207. b:=0;
  208. for I:=-3 to RecordLength-2 do
  209. b:=byte(b+RawData[I]);
  210. SetChecksumByte($100-b);
  211. end;
  212. function TOmfRawRecord.VerifyChecksumByte: boolean;
  213. var
  214. I: Integer;
  215. b: Byte;
  216. begin
  217. { according to the OMF spec, some tools always write a 0 rather than
  218. computing the checksum, so it should also be accepted as correct }
  219. if ChecksumByte=0 then
  220. exit(true);
  221. b:=0;
  222. for I:=-3 to RecordLength-1 do
  223. b:=byte(b+RawData[I]);
  224. Result:=(b=0);
  225. end;
  226. procedure TOmfRawRecord.ReadFrom(aReader: TObjectReader);
  227. begin
  228. aReader.read(RawData, 3);
  229. aReader.read(RawData[0], RecordLength);
  230. end;
  231. procedure TOmfRawRecord.WriteTo(aWriter: TObjectWriter);
  232. begin
  233. aWriter.write(RawData, RecordLength+3);
  234. end;
  235. { TOmfRecord_THEADR }
  236. procedure TOmfRecord_THEADR.DecodeFrom(RawRecord: TOmfRawRecord);
  237. begin
  238. RawRecord.ReadStringAt(0,FModuleName);
  239. end;
  240. procedure TOmfRecord_THEADR.EncodeTo(RawRecord: TOmfRawRecord);
  241. var
  242. NextOfs: Integer;
  243. begin
  244. RawRecord.RecordType:=RT_THEADR;
  245. NextOfs:=RawRecord.WriteStringAt(0,ModuleName);
  246. RawRecord.RecordLength:=NextOfs+1;
  247. RawRecord.CalculateChecksumByte;
  248. end;
  249. { TOmfRecord_COMENT }
  250. function TOmfRecord_COMENT.GetNoList: Boolean;
  251. begin
  252. Result:=(CommentType and $40)<>0;
  253. end;
  254. function TOmfRecord_COMENT.GetNoPurge: Boolean;
  255. begin
  256. Result:=(CommentType and $80)<>0;
  257. end;
  258. procedure TOmfRecord_COMENT.SetNoList(AValue: Boolean);
  259. begin
  260. if AValue then
  261. CommentType:=CommentType or $40
  262. else
  263. CommentType:=CommentType and $BF;
  264. end;
  265. procedure TOmfRecord_COMENT.SetNoPurge(AValue: Boolean);
  266. begin
  267. if AValue then
  268. CommentType:=CommentType or $80
  269. else
  270. CommentType:=CommentType and $7F;
  271. end;
  272. procedure TOmfRecord_COMENT.DecodeFrom(RawRecord: TOmfRawRecord);
  273. begin
  274. if RawRecord.RecordLength<3 then
  275. internalerror(2015033104);
  276. CommentType:=RawRecord.RawData[0];
  277. CommentClass:=RawRecord.RawData[1];
  278. SetLength(FCommentString,RawRecord.RecordLength-3);
  279. UniqueString(FCommentString);
  280. Move(RawRecord.RawData[2],FCommentString[1],Length(FCommentString));
  281. end;
  282. procedure TOmfRecord_COMENT.EncodeTo(RawRecord: TOmfRawRecord);
  283. begin
  284. RawRecord.RecordType:=RT_COMENT;
  285. if (Length(FCommentString)+3)>High(RawRecord.RawData) then
  286. internalerror(2015033105);
  287. RawRecord.RecordLength:=Length(FCommentString)+3;
  288. RawRecord.RawData[0]:=CommentType;
  289. RawRecord.RawData[1]:=CommentClass;
  290. Move(FCommentString[1],RawRecord.RawData[2],Length(FCommentString));
  291. RawRecord.CalculateChecksumByte;
  292. end;
  293. end.