omfbase.pas 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959
  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. cclasses,
  24. owbase;
  25. const
  26. { OMF record types }
  27. RT_THEADR = $80; { Translator Header Record }
  28. RT_LHEADR = $82; { Library Module Header Record }
  29. RT_COMENT = $88; { Comment Record }
  30. RT_MODEND = $8A; { Module End Record }
  31. RT_MODEND32 = $8B;
  32. RT_EXTDEF = $8C; { External Names Definition Record }
  33. RT_PUBDEF = $90; { Public Names Definition Record }
  34. RT_PUBDEF32 = $91;
  35. RT_LINNUM = $94; { Line Numbers Record }
  36. RT_LINNUM32 = $95;
  37. RT_LNAMES = $96; { List of Names Record }
  38. RT_SEGDEF = $98; { Segment Definition Record }
  39. RT_SEGDEF32 = $99;
  40. RT_GRPDEF = $9A; { Group Definition Record }
  41. RT_FIXUPP = $9C; { Fixup Record }
  42. RT_FIXUPP32 = $9D;
  43. RT_LEDATA = $A0; { Logical Enumerated Data Record }
  44. RT_LEDATA32 = $A1;
  45. RT_LIDATA = $A2; { Logical Iterated Data Record }
  46. RT_LIDATA32 = $A3;
  47. RT_COMDEF = $B0; { Communal Names Definition Record }
  48. RT_BAKPAT = $B2; { Backpatch Record }
  49. RT_BAKPAT32 = $B3;
  50. RT_LEXTDEF = $B4; { Local External Names Definition Record }
  51. RT_LEXTDEF32 = $B5;
  52. RT_LPUBDEF = $B6; { Local Public Names Definition Record }
  53. RT_LPUBDEF32 = $B7;
  54. RT_LCOMDEF = $B8; { Local Communal Names Definition Record }
  55. RT_CEXTDEF = $BC; { COMDAT External Names Definition Record }
  56. RT_COMDAT = $C2; { Initialized Communal Data Record }
  57. RT_COMDAT32 = $C3;
  58. RT_LINSYM = $C4; { Symbol Line Numbers Record }
  59. RT_LINSYM32 = $C5;
  60. RT_ALIAS = $C6; { Alias Definition Record }
  61. RT_NBKPAT = $C8; { Named Backpatch Record }
  62. RT_NBKPAT32 = $C9;
  63. RT_LLNAMES = $CA; { Local Logical Names Definition Record }
  64. RT_VERNUM = $CC; { OMF Version Number Record }
  65. RT_VENDEXT = $CE; { Vendor-specific OMF Extension Record }
  66. { OMF comment class }
  67. CC_Translator = $00; { language translator (compiler or assembler) name }
  68. CC_IntelCopyright = $01;
  69. CC_IntelReservedRangeStart = $02;
  70. CC_IntelReservedRangeEnd = $9B;
  71. CC_LibrarySpecifierObsolete = $81;
  72. CC_MsDosVersionObsolete = $9C;
  73. CC_MemoryModel = $9D;
  74. CC_DOSSEG = $9E;
  75. CC_DefaultLibrarySearchName = $9F;
  76. CC_OmfExtension = $A0;
  77. CC_NewOmfExtension = $A1;
  78. CC_LinkPassSeparator = $A2;
  79. CC_LIBMOD = $A3;
  80. CC_EXESTR = $A4;
  81. CC_INCERR = $A6;
  82. CC_NOPAD = $A7;
  83. CC_WKEXT = $A8;
  84. CC_LZEXT = $A9;
  85. CC_Comment = $DA;
  86. CC_Compiler = $DB;
  87. CC_Date = $DC;
  88. CC_Timestamp = $DD;
  89. CC_User = $DF;
  90. CC_DependencyFileBorland = $E9;
  91. CC_CommandLineMicrosoft = $FF;
  92. type
  93. TOmfSegmentAlignment = (
  94. saAbsolute = 0,
  95. saRelocatableByteAligned = 1,
  96. saRelocatableWordAligned = 2,
  97. saRelocatableParaAligned = 3,
  98. saRelocatablePageAligned = 4, { 32-bit linkers extension }
  99. saRelocatableDWordAligned = 5, { 32-bit linkers extension }
  100. saNotSupported = 6,
  101. saNotDefined = 7);
  102. TOmfSegmentCombination = (
  103. scPrivate = 0,
  104. scReserved1 = 1,
  105. scPublic = 2,
  106. scReserved3 = 3,
  107. scPublic4 = 4, { same as scPublic }
  108. scStack = 5,
  109. scCommon = 6,
  110. scPublic7 = 7); { same as scPublic }
  111. TOmfSegmentUse = (suUse16, suUse32);
  112. TOmfFixupThread = (ftThread0, ftThread1, ftThread2, ftThread3);
  113. TOmfFixupMode = (fmSelfRelative, fmSegmentRelative);
  114. TOmfFixupLocationType = (
  115. fltLoByte = 0, { low 8 bits of 16-bit offset }
  116. fltOffset = 1, { 16-bit offset }
  117. fltBase = 2, { 16-bit base (segment) }
  118. fltFarPointer = 3, { 16-bit base:16-bit offset }
  119. fltHiByte = 4, { high 8 bits of 16-bit offset }
  120. fltLoaderResolvedOffset = 5, { PharLap: Offset32 }
  121. fltUndefined6 = 6, { PharLap: Pointer48 }
  122. fltUndefined7 = 7,
  123. fltUndefined8 = 8,
  124. fltOffset32 = 9, { 32-bit offset }
  125. fltUndefined10 = 10,
  126. fltFarPointer48 = 11, { 16-bit base:32-bit offset }
  127. fltUndefined12 = 12,
  128. fltLoaderResolvedOffset32 = 13,
  129. fltUndefined14 = 14,
  130. fltUndefined15 = 15);
  131. TOmfFixupFrameMethod = (
  132. ffmSegmentIndex = 0, { SI(<segment name>) - The frame is the canonic frame of the logical
  133. segment segment defined by the index }
  134. ffmGroupIndex = 1, { GI(<group name>) - The frame is the canonic frame of the group
  135. (= the canonic frame of the logical segment from the group,
  136. located at the lowest memory address) }
  137. ffmExternalIndex = 2, { EI(<symbol name>) - The frame is determined depending on the external's public definition:
  138. * if the symbol is defined relative to a logical segment and no defined group,
  139. the frame of the logical segment is used
  140. * if the symbol is defined absolutely, without reference to a logical segment and
  141. no defined group, the FRAME NUMBER from the symbol's PUBDEF record is used
  142. * regardless of how the symbol is specified, if there's an associated group,
  143. that group's canonic frame is used }
  144. ffmFrameNumber = 3, { <FRAME NUMBER> - The frame is a directly specified constant. }
  145. ffmLocation = 4, { LOCATION - The frame is determined by the location (i.e. the canonic frame of the logical
  146. segment where the fixup location is) }
  147. ffmTarget = 5, { TARGET - The frame is determined by the target. }
  148. ffmNone = 6, { NONE - There is no frame. Used for 8089 self-relative references. }
  149. ffmUndefined = 7);
  150. TOmfFixupTargetMethod = (
  151. ftmSegmentIndex = 0, { SI(<segment name>),<displacement> }
  152. ftmGroupIndex = 1, { GI(<group name>),<displacement> }
  153. ftmExternalIndex = 2, { EI(<symbol name>),<displacement> }
  154. ftmFrameNumber = 3, { <FRAME NUMBER>,<displacement> }
  155. ftmSegmentIndexNoDisp = 4, { SI(<segment name>) }
  156. ftmGroupIndexNoDisp = 5, { GI(<group name>) }
  157. ftmExternalIndexNoDisp = 6, { EI(<symbol name>) }
  158. ftmFrameNumberNoDisp = 7); { <FRAME NUMBER> }
  159. { TOmfOrderedNameCollection }
  160. TOmfOrderedNameCollection = class
  161. private
  162. FStringList: array of string;
  163. function GetCount: Integer;
  164. function GetString(Index: Integer): string;
  165. procedure SetString(Index: Integer; AValue: string);
  166. public
  167. function Add(const S: string): Integer;
  168. procedure Clear;
  169. property Strings [Index: Integer]: string read GetString write SetString; default;
  170. property Count: Integer read GetCount;
  171. end;
  172. { TOmfRawRecord }
  173. TOmfRawRecord = class
  174. private
  175. function GetChecksumByte: Byte;
  176. function GetRecordLength: Word;
  177. function GetRecordType: Byte;
  178. procedure SetChecksumByte(AValue: Byte);
  179. procedure SetRecordLength(AValue: Word);
  180. procedure SetRecordType(AValue: Byte);
  181. public
  182. RawData: array [-3..65535] of Byte;
  183. property RecordType: Byte read GetRecordType write SetRecordType;
  184. property RecordLength: Word read GetRecordLength write SetRecordLength;
  185. function ReadStringAt(Offset: Integer; out s: string): Integer;
  186. function WriteStringAt(Offset: Integer; s: string): Integer;
  187. function ReadIndexedRef(Offset: Integer; out IndexedRef: Integer): Integer;
  188. function WriteIndexedRef(Offset: Integer; IndexedRef: Integer): Integer;
  189. procedure CalculateChecksumByte;
  190. function VerifyChecksumByte: boolean;
  191. property ChecksumByte: Byte read GetChecksumByte write SetChecksumByte;
  192. procedure ReadFrom(aReader: TObjectReader);
  193. procedure WriteTo(aWriter: TObjectWriter);
  194. end;
  195. { TOmfParsedRecord }
  196. TOmfParsedRecord = class
  197. public
  198. procedure DecodeFrom(RawRecord: TOmfRawRecord);virtual;abstract;
  199. procedure EncodeTo(RawRecord: TOmfRawRecord);virtual;abstract;
  200. end;
  201. { TOmfRecord_THEADR }
  202. TOmfRecord_THEADR = class(TOmfParsedRecord)
  203. private
  204. FModuleName: string;
  205. public
  206. procedure DecodeFrom(RawRecord: TOmfRawRecord);override;
  207. procedure EncodeTo(RawRecord: TOmfRawRecord);override;
  208. property ModuleName: string read FModuleName write FModuleName;
  209. end;
  210. { TOmfRecord_COMENT }
  211. TOmfRecord_COMENT = class(TOmfParsedRecord)
  212. private
  213. FCommentType: Byte;
  214. FCommentClass: Byte;
  215. FCommentString: string;
  216. function GetNoList: Boolean;
  217. function GetNoPurge: Boolean;
  218. procedure SetNoList(AValue: Boolean);
  219. procedure SetNoPurge(AValue: Boolean);
  220. public
  221. procedure DecodeFrom(RawRecord: TOmfRawRecord);override;
  222. procedure EncodeTo(RawRecord: TOmfRawRecord);override;
  223. property CommentType: Byte read FCommentType write FCommentType;
  224. property CommentClass: Byte read FCommentClass write FCommentClass;
  225. property CommentString: string read FCommentString write FCommentString;
  226. property NoPurge: Boolean read GetNoPurge write SetNoPurge;
  227. property NoList: Boolean read GetNoList write SetNoList;
  228. end;
  229. { TOmfRecord_LNAMES }
  230. TOmfRecord_LNAMES = class(TOmfParsedRecord)
  231. private
  232. FNames: TOmfOrderedNameCollection;
  233. FNextIndex: Integer;
  234. public
  235. constructor Create;
  236. procedure DecodeFrom(RawRecord: TOmfRawRecord);override;
  237. procedure EncodeTo(RawRecord: TOmfRawRecord);override;
  238. property Names: TOmfOrderedNameCollection read FNames write FNames;
  239. property NextIndex: Integer read FNextIndex write FNextIndex;
  240. end;
  241. { TOmfRecord_SEGDEF }
  242. TOmfRecord_SEGDEF = class(TOmfParsedRecord)
  243. private
  244. FAlignment: TOmfSegmentAlignment;
  245. FCombination: TOmfSegmentCombination;
  246. FUse: TOmfSegmentUse;
  247. FFrameNumber: Word;
  248. FOffset: Byte;
  249. FIs32Bit: Boolean;
  250. FSegmentLength: Int64; { int64, because it can be 2**32 }
  251. FSegmentNameIndex: Integer;
  252. FClassNameIndex: Integer;
  253. FOverlayNameIndex: Integer;
  254. public
  255. procedure DecodeFrom(RawRecord: TOmfRawRecord);override;
  256. procedure EncodeTo(RawRecord: TOmfRawRecord);override;
  257. property Alignment: TOmfSegmentAlignment read FAlignment write FAlignment;
  258. property Combination: TOmfSegmentCombination read FCombination write FCombination;
  259. property Use: TOmfSegmentUse read FUse write FUse;
  260. property FrameNumber: Word read FFrameNumber write FFrameNumber;
  261. property Offset: Byte read FOffset write FOffset;
  262. property Is32Bit: Boolean read FIs32Bit write FIs32Bit;
  263. property SegmentLength: Int64 read FSegmentLength write FSegmentLength;
  264. property SegmentNameIndex: Integer read FSegmentNameIndex write FSegmentNameIndex;
  265. property ClassNameIndex: Integer read FClassNameIndex write FClassNameIndex;
  266. property OverlayNameIndex: Integer read FOverlayNameIndex write FOverlayNameIndex;
  267. end;
  268. TSegmentList = array of Integer;
  269. { TOmfRecord_GRPDEF }
  270. TOmfRecord_GRPDEF = class(TOmfParsedRecord)
  271. private
  272. FGroupNameIndex: Integer;
  273. FSegmentList: TSegmentList;
  274. public
  275. procedure DecodeFrom(RawRecord: TOmfRawRecord);override;
  276. procedure EncodeTo(RawRecord: TOmfRawRecord);override;
  277. property GroupNameIndex: Integer read FGroupNameIndex write FGroupNameIndex;
  278. property SegmentList: TSegmentList read FSegmentList write FSegmentList;
  279. end;
  280. { TOmfRecord_MODEND }
  281. TOmfRecord_MODEND = class(TOmfParsedRecord)
  282. private
  283. FIs32Bit: Boolean;
  284. FIsMainModule: Boolean;
  285. FHasStartAddress: Boolean;
  286. FSegmentBit: Boolean;
  287. FLogicalStartAddress: Boolean;
  288. public
  289. procedure DecodeFrom(RawRecord: TOmfRawRecord);override;
  290. procedure EncodeTo(RawRecord: TOmfRawRecord);override;
  291. property Is32Bit: Boolean read FIs32Bit write FIs32Bit;
  292. property IsMainModule: Boolean read FIsMainModule write FIsMainModule;
  293. property HasStartAddress: Boolean read FHasStartAddress write FHasStartAddress;
  294. property SegmentBit: Boolean read FSegmentBit write FSegmentBit;
  295. property LogicalStartAddress: Boolean read FLogicalStartAddress write FLogicalStartAddress;
  296. end;
  297. { TOmfSubRecord_FIXUP }
  298. TOmfSubRecord_FIXUP = class
  299. private
  300. FIs32Bit: Boolean;
  301. FMode: TOmfFixupMode;
  302. FLocationType: TOmfFixupLocationType;
  303. FLocationOffset: DWord;
  304. FDataRecordStartOffset: DWord;
  305. FTargetDeterminedByThread: Boolean;
  306. FTargetThread: TOmfFixupThread;
  307. FTargetThreadDisplacementPresent: Boolean;
  308. FTargetMethod: TOmfFixupTargetMethod;
  309. FTargetDatum: Integer;
  310. FTargetDisplacement: DWord;
  311. FFrameDeterminedByThread: Boolean;
  312. FFrameThread: TOmfFixupThread;
  313. FFrameMethod: TOmfFixupFrameMethod;
  314. FFrameDatum: Integer;
  315. function GetDataRecordOffset: Integer;
  316. procedure SetDataRecordOffset(AValue: Integer);
  317. public
  318. function ReadAt(RawRecord: TOmfRawRecord; Offset: Integer): Integer;
  319. function WriteAt(RawRecord: TOmfRawRecord; Offset: Integer): Integer;
  320. property Is32Bit: Boolean read FIs32Bit write FIs32Bit;
  321. property Mode: TOmfFixupMode read FMode write FMode;
  322. property LocationType: TOmfFixupLocationType read FLocationType write FLocationType;
  323. property LocationOffset: DWord read FLocationOffset write FLocationOffset;
  324. property DataRecordStartOffset: DWord read FDataRecordStartOffset write FDataRecordStartOffset;
  325. property DataRecordOffset: Integer read GetDataRecordOffset write SetDataRecordOffset;
  326. property TargetDeterminedByThread: Boolean read FTargetDeterminedByThread write FTargetDeterminedByThread;
  327. property TargetThread: TOmfFixupThread read FTargetThread write FTargetThread;
  328. property TargetThreadDisplacementPresent: Boolean read FTargetThreadDisplacementPresent write FTargetThreadDisplacementPresent;
  329. property TargetMethod: TOmfFixupTargetMethod read FTargetMethod write FTargetMethod;
  330. property TargetDatum: Integer read FTargetDatum write FTargetDatum;
  331. property TargetDisplacement: DWord read FTargetDisplacement write FTargetDisplacement;
  332. property FrameDeterminedByThread: Boolean read FFrameDeterminedByThread write FFrameDeterminedByThread;
  333. property FrameThread: TOmfFixupThread read FFrameThread write FFrameThread;
  334. property FrameMethod: TOmfFixupFrameMethod read FFrameMethod write FFrameMethod;
  335. property FrameDatum: Integer read FFrameDatum write FFrameDatum;
  336. end;
  337. implementation
  338. uses
  339. verbose;
  340. { TOmfOrderedNameCollection }
  341. function TOmfOrderedNameCollection.GetString(Index: Integer): string;
  342. begin
  343. Result:=FStringList[Index-1];
  344. end;
  345. function TOmfOrderedNameCollection.GetCount: Integer;
  346. begin
  347. Result:=Length(FStringList);
  348. end;
  349. procedure TOmfOrderedNameCollection.SetString(Index: Integer; AValue: string);
  350. begin
  351. FStringList[Index-1]:=AValue;
  352. end;
  353. function TOmfOrderedNameCollection.Add(const S: string): Integer;
  354. begin
  355. Result:=Length(FStringList)+1;
  356. SetLength(FStringList,Result);
  357. FStringList[Result-1]:=S;
  358. end;
  359. procedure TOmfOrderedNameCollection.Clear;
  360. begin
  361. SetLength(FStringList,0);
  362. end;
  363. { TOmfRawRecord }
  364. function TOmfRawRecord.GetRecordType: Byte;
  365. begin
  366. Result:=RawData[-3];
  367. end;
  368. procedure TOmfRawRecord.SetRecordType(AValue: Byte);
  369. begin
  370. RawData[-3]:=AValue;
  371. end;
  372. function TOmfRawRecord.GetRecordLength: Word;
  373. begin
  374. Result:=RawData[-2] or (RawData[-1] shl 8);
  375. end;
  376. procedure TOmfRawRecord.SetRecordLength(AValue: Word);
  377. begin
  378. RawData[-2]:=Byte(AValue);
  379. RawData[-1]:=Byte(AValue shr 8);
  380. end;
  381. function TOmfRawRecord.ReadStringAt(Offset: Integer; out s: string): Integer;
  382. var
  383. len: Byte;
  384. begin
  385. len:=RawData[Offset];
  386. Result:=Offset+len+1;
  387. if result>RecordLength then
  388. internalerror(2015033103);
  389. SetLength(s, len);
  390. UniqueString(s);
  391. Move(RawData[Offset+1],s[1],len);
  392. end;
  393. function TOmfRawRecord.WriteStringAt(Offset: Integer; s: string): Integer;
  394. begin
  395. if Length(s)>255 then
  396. internalerror(2015033101);
  397. result:=Offset+Length(s)+1;
  398. if result>High(RawData) then
  399. internalerror(2015033102);
  400. RawData[Offset]:=Length(s);
  401. Move(s[1], RawData[Offset+1], Length(s));
  402. end;
  403. function TOmfRawRecord.ReadIndexedRef(Offset: Integer; out IndexedRef: Integer): Integer;
  404. begin
  405. Result:=Offset+1;
  406. if result>RecordLength then
  407. internalerror(2015033103);
  408. IndexedRef:=RawData[Offset];
  409. if IndexedRef<=$7f then
  410. exit;
  411. Result:=Offset+2;
  412. if result>RecordLength then
  413. internalerror(2015033103);
  414. IndexedRef:=((IndexedRef and $7f) shl 8)+RawData[Offset+1];
  415. end;
  416. function TOmfRawRecord.WriteIndexedRef(Offset: Integer; IndexedRef: Integer): Integer;
  417. begin
  418. if (IndexedRef<0) or (IndexedRef>$7FFF) then
  419. internalerror(2015040303);
  420. if IndexedRef<=$7f then
  421. begin
  422. Result:=Offset+1;
  423. if Result>High(RawData) then
  424. internalerror(2015033102);
  425. RawData[Offset]:=IndexedRef;
  426. end
  427. else
  428. begin
  429. Result:=Offset+2;
  430. if Result>High(RawData) then
  431. internalerror(2015033102);
  432. RawData[Offset]:=$80+(IndexedRef shr 8);
  433. RawData[Offset+1]:=Byte(IndexedRef);
  434. end;
  435. end;
  436. function TOmfRawRecord.GetChecksumByte: Byte;
  437. begin
  438. if RecordLength>0 then
  439. Result:=RawData[RecordLength-1]
  440. else
  441. Result:=0;
  442. end;
  443. procedure TOmfRawRecord.SetChecksumByte(AValue: Byte);
  444. begin
  445. if RecordLength>0 then
  446. RawData[RecordLength-1]:=AValue;
  447. end;
  448. procedure TOmfRawRecord.CalculateChecksumByte;
  449. var
  450. I: Integer;
  451. b: Byte;
  452. begin
  453. b:=0;
  454. for I:=-3 to RecordLength-2 do
  455. b:=byte(b+RawData[I]);
  456. SetChecksumByte($100-b);
  457. end;
  458. function TOmfRawRecord.VerifyChecksumByte: boolean;
  459. var
  460. I: Integer;
  461. b: Byte;
  462. begin
  463. { according to the OMF spec, some tools always write a 0 rather than
  464. computing the checksum, so it should also be accepted as correct }
  465. if ChecksumByte=0 then
  466. exit(true);
  467. b:=0;
  468. for I:=-3 to RecordLength-1 do
  469. b:=byte(b+RawData[I]);
  470. Result:=(b=0);
  471. end;
  472. procedure TOmfRawRecord.ReadFrom(aReader: TObjectReader);
  473. begin
  474. aReader.read(RawData, 3);
  475. aReader.read(RawData[0], RecordLength);
  476. end;
  477. procedure TOmfRawRecord.WriteTo(aWriter: TObjectWriter);
  478. begin
  479. aWriter.write(RawData, RecordLength+3);
  480. end;
  481. { TOmfRecord_THEADR }
  482. procedure TOmfRecord_THEADR.DecodeFrom(RawRecord: TOmfRawRecord);
  483. begin
  484. RawRecord.ReadStringAt(0,FModuleName);
  485. end;
  486. procedure TOmfRecord_THEADR.EncodeTo(RawRecord: TOmfRawRecord);
  487. var
  488. NextOfs: Integer;
  489. begin
  490. RawRecord.RecordType:=RT_THEADR;
  491. NextOfs:=RawRecord.WriteStringAt(0,ModuleName);
  492. RawRecord.RecordLength:=NextOfs+1;
  493. RawRecord.CalculateChecksumByte;
  494. end;
  495. { TOmfRecord_COMENT }
  496. function TOmfRecord_COMENT.GetNoList: Boolean;
  497. begin
  498. Result:=(CommentType and $40)<>0;
  499. end;
  500. function TOmfRecord_COMENT.GetNoPurge: Boolean;
  501. begin
  502. Result:=(CommentType and $80)<>0;
  503. end;
  504. procedure TOmfRecord_COMENT.SetNoList(AValue: Boolean);
  505. begin
  506. if AValue then
  507. CommentType:=CommentType or $40
  508. else
  509. CommentType:=CommentType and $BF;
  510. end;
  511. procedure TOmfRecord_COMENT.SetNoPurge(AValue: Boolean);
  512. begin
  513. if AValue then
  514. CommentType:=CommentType or $80
  515. else
  516. CommentType:=CommentType and $7F;
  517. end;
  518. procedure TOmfRecord_COMENT.DecodeFrom(RawRecord: TOmfRawRecord);
  519. begin
  520. if RawRecord.RecordLength<3 then
  521. internalerror(2015033104);
  522. CommentType:=RawRecord.RawData[0];
  523. CommentClass:=RawRecord.RawData[1];
  524. SetLength(FCommentString,RawRecord.RecordLength-3);
  525. UniqueString(FCommentString);
  526. Move(RawRecord.RawData[2],FCommentString[1],Length(FCommentString));
  527. end;
  528. procedure TOmfRecord_COMENT.EncodeTo(RawRecord: TOmfRawRecord);
  529. begin
  530. RawRecord.RecordType:=RT_COMENT;
  531. if (Length(FCommentString)+3)>High(RawRecord.RawData) then
  532. internalerror(2015033105);
  533. RawRecord.RecordLength:=Length(FCommentString)+3;
  534. RawRecord.RawData[0]:=CommentType;
  535. RawRecord.RawData[1]:=CommentClass;
  536. Move(FCommentString[1],RawRecord.RawData[2],Length(FCommentString));
  537. RawRecord.CalculateChecksumByte;
  538. end;
  539. { TOmfRecord_LNAMES }
  540. constructor TOmfRecord_LNAMES.Create;
  541. begin
  542. FNextIndex:=1;
  543. end;
  544. procedure TOmfRecord_LNAMES.DecodeFrom(RawRecord: TOmfRawRecord);
  545. begin
  546. {TODO: implement}
  547. internalerror(2015040101);
  548. end;
  549. procedure TOmfRecord_LNAMES.EncodeTo(RawRecord: TOmfRawRecord);
  550. const
  551. RecordLengthLimit = 1024;
  552. var
  553. Len,LastIncludedIndex,NextOfs,I: Integer;
  554. begin
  555. RawRecord.RecordType:=RT_LNAMES;
  556. { find out how many strings can we include until we reach the length limit }
  557. Len:=1;
  558. LastIncludedIndex:=NextIndex-1;
  559. repeat
  560. Inc(LastIncludedIndex);
  561. Inc(Len,Length(Names[LastIncludedIndex])+1);
  562. until (LastIncludedIndex>=Names.Count) or ((Len+Length(Names[LastIncludedIndex+1])+1)>=RecordLengthLimit);
  563. { write the strings... }
  564. NextOfs:=0;
  565. for I:=NextIndex to LastIncludedIndex do
  566. NextOfs:=RawRecord.WriteStringAt(NextOfs,Names[I]);
  567. RawRecord.RecordLength:=Len;
  568. RawRecord.CalculateChecksumByte;
  569. { update NextIndex }
  570. NextIndex:=LastIncludedIndex+1;
  571. end;
  572. { TOmfRecord_SEGDEF }
  573. procedure TOmfRecord_SEGDEF.DecodeFrom(RawRecord: TOmfRawRecord);
  574. var
  575. B: Byte;
  576. Big: Boolean;
  577. NextOfs: Integer;
  578. MinLen: Integer;
  579. begin
  580. if not (RawRecord.RecordType in [RT_SEGDEF,RT_SEGDEF32]) then
  581. internalerror(2015040301);
  582. Is32Bit:=RawRecord.RecordType=RT_SEGDEF32;
  583. MinLen:=7; { b(1)+seglength(2..4)+segnameindex(1..2)+classnameindex(1..2)+overlaynameindex(1..2)+checksum }
  584. if Is32Bit then
  585. inc(MinLen,2);
  586. if RawRecord.RecordLength<MinLen then
  587. internalerror(2015040305);
  588. B:=RawRecord.RawData[0];
  589. Alignment:=TOmfSegmentAlignment(B shr 5);
  590. Combination:=TOmfSegmentCombination((B shr 2) and 7);
  591. Big:=(B and 2)<>0;
  592. Use:=TOmfSegmentUse(B and 1);
  593. NextOfs:=1;
  594. if Alignment=saAbsolute then
  595. begin
  596. inc(MinLen,3);
  597. if RawRecord.RecordLength<MinLen then
  598. internalerror(2015040305);
  599. FrameNumber:=RawRecord.RawData[1]+(RawRecord.RawData[2] shl 8);
  600. Offset:=RawRecord.RawData[3];
  601. NextOfs:=4;
  602. end
  603. else
  604. begin
  605. FrameNumber:=0;
  606. Offset:=0;
  607. end;
  608. if Is32Bit then
  609. begin
  610. SegmentLength:=RawRecord.RawData[NextOfs]+
  611. (RawRecord.RawData[NextOfs+1] shl 8)+
  612. (RawRecord.RawData[NextOfs+2] shl 16)+
  613. (RawRecord.RawData[NextOfs+3] shl 24);
  614. if Big then
  615. if SegmentLength=0 then
  616. SegmentLength:=4294967296
  617. else
  618. internalerror(2015040306);
  619. Inc(NextOfs,4);
  620. end
  621. else
  622. begin
  623. SegmentLength:=RawRecord.RawData[NextOfs]+(RawRecord.RawData[NextOfs+1] shl 8);
  624. if Big then
  625. if SegmentLength=0 then
  626. SegmentLength:=65536
  627. else
  628. internalerror(2015040306);
  629. Inc(NextOfs,2);
  630. end;
  631. NextOfs:=RawRecord.ReadIndexedRef(NextOfs,FSegmentNameIndex);
  632. NextOfs:=RawRecord.ReadIndexedRef(NextOfs,FClassNameIndex);
  633. NextOfs:=RawRecord.ReadIndexedRef(NextOfs,FOverlayNameIndex);
  634. end;
  635. procedure TOmfRecord_SEGDEF.EncodeTo(RawRecord: TOmfRawRecord);
  636. var
  637. Big: Boolean;
  638. NextOfs: Integer;
  639. begin
  640. if Is32Bit then
  641. begin
  642. RawRecord.RecordType:=RT_SEGDEF32;
  643. if SegmentLength>4294967296 then
  644. internalerror(2015040302);
  645. Big:=SegmentLength=4294967296;
  646. end
  647. else
  648. begin
  649. RawRecord.RecordType:=RT_SEGDEF;
  650. if SegmentLength>65536 then
  651. internalerror(2015040302);
  652. Big:=SegmentLength=65536;
  653. end;
  654. RawRecord.RawData[0]:=(Ord(Alignment) shl 5) or (Ord(Combination) shl 2) or (Ord(Big) shl 1) or Ord(Use);
  655. NextOfs:=1;
  656. if Alignment=saAbsolute then
  657. begin
  658. RawRecord.RawData[1]:=Byte(FrameNumber);
  659. RawRecord.RawData[2]:=Byte(FrameNumber shr 8);
  660. RawRecord.RawData[3]:=Offset;
  661. NextOfs:=4;
  662. end;
  663. if Is32Bit then
  664. begin
  665. RawRecord.RawData[NextOfs]:=Byte(SegmentLength);
  666. RawRecord.RawData[NextOfs+1]:=Byte(SegmentLength shr 8);
  667. RawRecord.RawData[NextOfs+2]:=Byte(SegmentLength shr 16);
  668. RawRecord.RawData[NextOfs+3]:=Byte(SegmentLength shr 24);
  669. Inc(NextOfs,4);
  670. end
  671. else
  672. begin
  673. RawRecord.RawData[NextOfs]:=Byte(SegmentLength);
  674. RawRecord.RawData[NextOfs+1]:=Byte(SegmentLength shr 8);
  675. Inc(NextOfs,2);
  676. end;
  677. NextOfs:=RawRecord.WriteIndexedRef(NextOfs,SegmentNameIndex);
  678. NextOfs:=RawRecord.WriteIndexedRef(NextOfs,ClassNameIndex);
  679. NextOfs:=RawRecord.WriteIndexedRef(NextOfs,OverlayNameIndex);
  680. RawRecord.RecordLength:=NextOfs+1;
  681. RawRecord.CalculateChecksumByte;
  682. end;
  683. { TOmfRecord_GRPDEF }
  684. procedure TOmfRecord_GRPDEF.DecodeFrom(RawRecord: TOmfRawRecord);
  685. begin
  686. {TODO: implement}
  687. internalerror(2015040101);
  688. end;
  689. procedure TOmfRecord_GRPDEF.EncodeTo(RawRecord: TOmfRawRecord);
  690. var
  691. NextOfs: Integer;
  692. Segment: Integer;
  693. begin
  694. RawRecord.RecordType:=RT_GRPDEF;
  695. NextOfs:=RawRecord.WriteIndexedRef(0,GroupNameIndex);
  696. for Segment in SegmentList do
  697. begin
  698. if NextOfs>High(RawRecord.RawData) then
  699. internalerror(2015040401);
  700. RawRecord.RawData[NextOfs]:=$ff;
  701. NextOfs:=RawRecord.WriteIndexedRef(NextOfs+1,Segment);
  702. end;
  703. RawRecord.RecordLength:=NextOfs+1;
  704. RawRecord.CalculateChecksumByte;
  705. end;
  706. { TOmfRecord_MODEND }
  707. procedure TOmfRecord_MODEND.DecodeFrom(RawRecord: TOmfRawRecord);
  708. begin
  709. {TODO: implement}
  710. internalerror(2015040101);
  711. end;
  712. procedure TOmfRecord_MODEND.EncodeTo(RawRecord: TOmfRawRecord);
  713. var
  714. ModTyp: Byte;
  715. NextOfs: Integer;
  716. begin
  717. if Is32Bit then
  718. RawRecord.RecordType:=RT_MODEND32
  719. else
  720. RawRecord.RecordType:=RT_MODEND;
  721. ModTyp:=(Ord(IsMainModule) shl 7)+(Ord(HasStartAddress) shl 6)+(Ord(SegmentBit) shl 5)+Ord(LogicalStartAddress);
  722. RawRecord.RawData[0]:=ModTyp;
  723. NextOfs:=1;
  724. if HasStartAddress then
  725. begin
  726. {TODO: implement writing a start address}
  727. internalerror(2015040101);
  728. end;
  729. RawRecord.RecordLength:=NextOfs+1;
  730. RawRecord.CalculateChecksumByte;
  731. end;
  732. { TOmfSubRecord_FIXUP }
  733. function TOmfSubRecord_FIXUP.GetDataRecordOffset: Integer;
  734. begin
  735. Result:=FLocationOffset-FDataRecordStartOffset;
  736. end;
  737. procedure TOmfSubRecord_FIXUP.SetDataRecordOffset(AValue: Integer);
  738. begin
  739. FLocationOffset:=AValue+FDataRecordStartOffset;
  740. end;
  741. function TOmfSubRecord_FIXUP.ReadAt(RawRecord: TOmfRawRecord; Offset: Integer): Integer;
  742. var
  743. Locat: Word;
  744. FixData: Byte;
  745. begin
  746. if (Offset+2)>High(RawRecord.RawData) then
  747. internalerror(2015040504);
  748. { unlike other fields in the OMF format, this one is big endian }
  749. Locat:=(RawRecord.RawData[Offset] shl 8) or RawRecord.RawData[Offset+1];
  750. FixData:=RawRecord.RawData[Offset+2];
  751. Inc(Offset,3);
  752. if (Locat and $8000)=0 then
  753. internalerror(2015040503);
  754. DataRecordOffset:=Locat and $3FF;
  755. LocationType:=TOmfFixupLocationType((Locat shr 10) and 15);
  756. Mode:=TOmfFixupMode((Locat shr 14) and 1);
  757. FrameDeterminedByThread:=(FixData and $80)<>0;
  758. TargetDeterminedByThread:=(FixData and $08)<>0;
  759. if FrameDeterminedByThread then
  760. FrameThread:=TOmfFixupThread((FixData shr 4) and 3)
  761. else
  762. FrameMethod:=TOmfFixupFrameMethod((FixData shr 4) and 7);
  763. if TargetDeterminedByThread then
  764. begin
  765. TargetThread:=TOmfFixupThread(FixData and 3);
  766. TargetThreadDisplacementPresent:=(FixData and $40)=0;
  767. end
  768. else
  769. TargetMethod:=TOmfFixupTargetMethod(FixData and 7);
  770. { read Frame Datum? }
  771. if not FrameDeterminedByThread and (FrameMethod in [ffmSegmentIndex,ffmGroupIndex,ffmExternalIndex,ffmFrameNumber]) then
  772. Offset:=RawRecord.ReadIndexedRef(Offset,FFrameDatum)
  773. else
  774. FrameDatum:=0;
  775. { read Target Datum? }
  776. if not TargetDeterminedByThread then
  777. Offset:=RawRecord.ReadIndexedRef(Offset,FTargetDatum)
  778. else
  779. TargetDatum:=0;
  780. { read Target Displacement? }
  781. if (TargetDeterminedByThread and TargetThreadDisplacementPresent) or
  782. (TargetMethod in [ftmSegmentIndex,ftmGroupIndex,ftmExternalIndex,ftmFrameNumber]) then
  783. begin
  784. if Is32Bit then
  785. begin
  786. if (Offset+3)>High(RawRecord.RawData) then
  787. internalerror(2015040504);
  788. TargetDisplacement := RawRecord.RawData[Offset]+
  789. (RawRecord.RawData[Offset+1] shl 8)+
  790. (RawRecord.RawData[Offset+2] shl 16)+
  791. (RawRecord.RawData[Offset+3] shl 24);
  792. Inc(Offset,4);
  793. end
  794. else
  795. begin
  796. if (Offset+1)>High(RawRecord.RawData) then
  797. internalerror(2015040504);
  798. TargetDisplacement := RawRecord.RawData[Offset]+
  799. (RawRecord.RawData[Offset+1] shl 8);
  800. Inc(Offset,2);
  801. end;
  802. end;
  803. Result:=Offset;
  804. end;
  805. function TOmfSubRecord_FIXUP.WriteAt(RawRecord: TOmfRawRecord; Offset: Integer): Integer;
  806. var
  807. Locat: Word;
  808. FixData: Byte;
  809. begin
  810. if (DataRecordOffset<0) or (DataRecordOffset>1023) then
  811. internalerror(2015040501);
  812. Locat:=$8000+(Ord(Mode) shl 14)+(Ord(LocationType) shl 10)+DataRecordOffset;
  813. { unlike other fields in the OMF format, this one is big endian }
  814. RawRecord.RawData[Offset]:=Byte(Locat shr 8);
  815. RawRecord.RawData[Offset+1]:=Byte(Locat);
  816. Inc(Offset, 2);
  817. FixData:=(Ord(FrameDeterminedByThread) shl 7)+(Ord(TargetDeterminedByThread) shl 3);
  818. if FrameDeterminedByThread then
  819. FixData:=FixData+(Ord(FrameThread) shl 4)
  820. else
  821. FixData:=FixData+(Ord(FrameMethod) shl 4);
  822. if TargetDeterminedByThread then
  823. FixData:=FixData+Ord(TargetThread)+(Ord(not TargetThreadDisplacementPresent) shl 2)
  824. else
  825. FixData:=FixData+Ord(TargetMethod);
  826. RawRecord.RawData[Offset]:=FixData;
  827. Inc(Offset);
  828. { save Frame Datum? }
  829. if not FrameDeterminedByThread and (FrameMethod in [ffmSegmentIndex,ffmGroupIndex,ffmExternalIndex,ffmFrameNumber]) then
  830. Offset:=RawRecord.WriteIndexedRef(Offset,FrameDatum);
  831. { save Target Datum? }
  832. if not TargetDeterminedByThread then
  833. Offset:=RawRecord.WriteIndexedRef(Offset,TargetDatum);
  834. { save Target Displacement? }
  835. if (TargetDeterminedByThread and TargetThreadDisplacementPresent) or
  836. (TargetMethod in [ftmSegmentIndex,ftmGroupIndex,ftmExternalIndex,ftmFrameNumber]) then
  837. begin
  838. if Is32Bit then
  839. begin
  840. RawRecord.RawData[Offset]:=Byte(TargetDisplacement);
  841. RawRecord.RawData[Offset+1]:=Byte(TargetDisplacement shr 8);
  842. RawRecord.RawData[Offset+2]:=Byte(TargetDisplacement shr 16);
  843. RawRecord.RawData[Offset+3]:=Byte(TargetDisplacement shr 24);
  844. Inc(Offset,4);
  845. end
  846. else
  847. begin
  848. if TargetDisplacement>$ffff then
  849. internalerror(2015040502);
  850. RawRecord.RawData[Offset]:=Byte(TargetDisplacement);
  851. RawRecord.RawData[Offset+1]:=Byte(TargetDisplacement shr 8);
  852. Inc(Offset,2);
  853. end;
  854. end;
  855. Result:=Offset;
  856. end;
  857. end.