ogomf.pas 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603
  1. {
  2. Copyright (c) 2015 by Nikolay Nikolov
  3. Contains the binary Relocatable Object Module Format (OMF) reader and writer
  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 ogomf;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. { common }
  23. cclasses,globtype,
  24. { target }
  25. systems,
  26. { assembler }
  27. cpuinfo,cpubase,aasmbase,assemble,link,
  28. { OMF definitions }
  29. omfbase,
  30. { output }
  31. ogbase,
  32. owbase;
  33. type
  34. { TOmfRelocation }
  35. TOmfRelocation = class(TObjRelocation)
  36. private
  37. FOmfFixup: TOmfSubRecord_FIXUP;
  38. public
  39. constructor CreateSymbol(ADataOffset:aword;s:TObjSymbol;Atyp:TObjRelocationType);
  40. destructor Destroy; override;
  41. property OmfFixup: TOmfSubRecord_FIXUP read FOmfFixup;
  42. end;
  43. { TOmfObjSection }
  44. TOmfObjSection = class(TObjSection)
  45. private
  46. FClassName: string;
  47. FOverlayName: string;
  48. FOmfAlignment: TOmfSegmentAlignment;
  49. FCombination: TOmfSegmentCombination;
  50. FUse: TOmfSegmentUse;
  51. FPrimaryGroup: string;
  52. public
  53. constructor create(AList:TFPHashObjectList;const Aname:string;Aalign:shortint;Aoptions:TObjSectionOptions);override;
  54. property ClassName: string read FClassName;
  55. property OverlayName: string read FOverlayName;
  56. property OmfAlignment: TOmfSegmentAlignment read FOmfAlignment;
  57. property Combination: TOmfSegmentCombination read FCombination;
  58. property Use: TOmfSegmentUse read FUse;
  59. property PrimaryGroup: string read FPrimaryGroup;
  60. end;
  61. { TOmfObjData }
  62. TOmfObjData = class(TObjData)
  63. private
  64. class function CodeSectionName(const aname:string): string;
  65. public
  66. constructor create(const n:string);override;
  67. function sectionname(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder):string;override;
  68. procedure writeReloc(Data:aint;len:aword;p:TObjSymbol;Reloctype:TObjRelocationType);override;
  69. end;
  70. { TOmfObjOutput }
  71. TOmfObjOutput = class(tObjOutput)
  72. private
  73. FLNames: TOmfOrderedNameCollection;
  74. FSegments: TFPHashObjectList;
  75. FGroups: TFPHashObjectList;
  76. procedure AddSegment(const name,segclass,ovlname: string;
  77. Alignment: TOmfSegmentAlignment; Combination: TOmfSegmentCombination;
  78. Use: TOmfSegmentUse; Size: aword);
  79. procedure AddGroup(const groupname: string; seglist: array of const);
  80. procedure WriteSections(Data:TObjData);
  81. procedure WriteSectionContentAndFixups(sec: TObjSection);
  82. procedure section_count_sections(p:TObject;arg:pointer);
  83. property LNames: TOmfOrderedNameCollection read FLNames;
  84. property Segments: TFPHashObjectList read FSegments;
  85. property Groups: TFPHashObjectList read FGroups;
  86. protected
  87. function writeData(Data:TObjData):boolean;override;
  88. public
  89. constructor create(AWriter:TObjectWriter);override;
  90. destructor Destroy;override;
  91. end;
  92. TOmfAssembler = class(tinternalassembler)
  93. constructor create(smart:boolean);override;
  94. end;
  95. implementation
  96. uses
  97. SysUtils,
  98. cutils,verbose,globals,
  99. fmodule,aasmtai,aasmdata,
  100. ogmap,
  101. version
  102. ;
  103. {****************************************************************************
  104. TOmfRelocation
  105. ****************************************************************************}
  106. constructor TOmfRelocation.CreateSymbol(ADataOffset: aword; s: TObjSymbol; Atyp: TObjRelocationType);
  107. begin
  108. inherited CreateSymbol(ADataOffset,s,Atyp);
  109. FOmfFixup:=TOmfSubRecord_FIXUP.Create;
  110. { dummy data, TODO: fix }
  111. FOmfFixup.LocationOffset:=ADataOffset;
  112. FOmfFixup.LocationType:=fltOffset;
  113. FOmfFixup.FrameDeterminedByThread:=False;
  114. FOmfFixup.TargetDeterminedByThread:=False;
  115. FOmfFixup.Mode:=fmSegmentRelative;
  116. FOmfFixup.TargetMethod:=ftmSegmentIndexNoDisp;
  117. FOmfFixup.TargetDatum:=3;
  118. FOmfFixup.FrameMethod:=ffmGroupIndex;
  119. FOmfFixup.FrameDatum:=1;
  120. end;
  121. destructor TOmfRelocation.Destroy;
  122. begin
  123. FOmfFixup.Free;
  124. inherited Destroy;
  125. end;
  126. {****************************************************************************
  127. TOmfObjSection
  128. ****************************************************************************}
  129. constructor TOmfObjSection.create(AList: TFPHashObjectList;
  130. const Aname: string; Aalign: shortint; Aoptions: TObjSectionOptions);
  131. var
  132. dgroup: Boolean;
  133. begin
  134. inherited create(AList, Aname, Aalign, Aoptions);
  135. FCombination:=scPublic;
  136. FUse:=suUse16;
  137. FOmfAlignment:=saRelocatableByteAligned;
  138. if oso_executable in Aoptions then
  139. begin
  140. FClassName:='code';
  141. dgroup:=(current_settings.x86memorymodel=mm_tiny);
  142. end
  143. else if Aname='stack' then
  144. begin
  145. FClassName:='stack';
  146. FCombination:=scStack;
  147. FOmfAlignment:=saRelocatableParaAligned;
  148. dgroup:=current_settings.x86memorymodel in (x86_near_data_models-[mm_tiny]);
  149. end
  150. else if Aname='heap' then
  151. begin
  152. FClassName:='heap';
  153. FOmfAlignment:=saRelocatableParaAligned;
  154. dgroup:=current_settings.x86memorymodel in x86_near_data_models;
  155. end
  156. else if Aname='bss' then
  157. begin
  158. FClassName:='bss';
  159. dgroup:=true;
  160. end
  161. else if Aname='data' then
  162. begin
  163. FClassName:='data';
  164. FOmfAlignment:=saRelocatableWordAligned;
  165. dgroup:=true;
  166. end
  167. else
  168. begin
  169. FClassName:='data';
  170. dgroup:=true;
  171. end;
  172. if dgroup then
  173. FPrimaryGroup:='dgroup'
  174. else
  175. FPrimaryGroup:='';
  176. end;
  177. {****************************************************************************
  178. TOmfObjData
  179. ****************************************************************************}
  180. class function TOmfObjData.CodeSectionName(const aname: string): string;
  181. begin
  182. {$ifdef i8086}
  183. if current_settings.x86memorymodel in x86_far_code_models then
  184. begin
  185. if cs_huge_code in current_settings.moduleswitches then
  186. result:=aname + '_TEXT'
  187. else
  188. result:=current_module.modulename^ + '_TEXT';
  189. end
  190. else
  191. {$endif}
  192. result:='text';
  193. end;
  194. constructor TOmfObjData.create(const n: string);
  195. begin
  196. inherited create(n);
  197. CObjSection:=TOmfObjSection;
  198. end;
  199. function TOmfObjData.sectionname(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder):string;
  200. const
  201. secnames : array[TAsmSectiontype] of string[length('__DATA, __datacoal_nt,coalesced')] = ('','',
  202. 'text',
  203. 'data',
  204. 'data',
  205. 'rodata',
  206. 'bss',
  207. 'tbss',
  208. 'pdata',
  209. 'text','data','data','data','data',
  210. 'stab',
  211. 'stabstr',
  212. 'idata2','idata4','idata5','idata6','idata7','edata',
  213. 'eh_frame',
  214. 'debug_frame','debug_info','debug_line','debug_abbrev',
  215. 'fpc',
  216. '',
  217. 'init',
  218. 'fini',
  219. 'objc_class',
  220. 'objc_meta_class',
  221. 'objc_cat_cls_meth',
  222. 'objc_cat_inst_meth',
  223. 'objc_protocol',
  224. 'objc_string_object',
  225. 'objc_cls_meth',
  226. 'objc_inst_meth',
  227. 'objc_cls_refs',
  228. 'objc_message_refs',
  229. 'objc_symbols',
  230. 'objc_category',
  231. 'objc_class_vars',
  232. 'objc_instance_vars',
  233. 'objc_module_info',
  234. 'objc_class_names',
  235. 'objc_meth_var_types',
  236. 'objc_meth_var_names',
  237. 'objc_selector_strs',
  238. 'objc_protocol_ext',
  239. 'objc_class_ext',
  240. 'objc_property',
  241. 'objc_image_info',
  242. 'objc_cstring_object',
  243. 'objc_sel_fixup',
  244. '__DATA,__objc_data',
  245. '__DATA,__objc_const',
  246. 'objc_superrefs',
  247. '__DATA, __datacoal_nt,coalesced',
  248. 'objc_classlist',
  249. 'objc_nlclasslist',
  250. 'objc_catlist',
  251. 'obcj_nlcatlist',
  252. 'objc_protolist',
  253. 'stack',
  254. 'heap'
  255. );
  256. begin
  257. if (atype=sec_user) then
  258. Result:=aname
  259. else if secnames[atype]='text' then
  260. Result:=CodeSectionName(aname)
  261. else
  262. Result:=secnames[atype];
  263. end;
  264. procedure TOmfObjData.writeReloc(Data:aint;len:aword;p:TObjSymbol;Reloctype:TObjRelocationType);
  265. var
  266. objreloc: TOmfRelocation;
  267. symaddr: AWord;
  268. begin
  269. { Write('writeReloc(', data, ',', len, ',');
  270. if p<>nil then
  271. write(p.Name)
  272. else
  273. write('nil');
  274. Writeln(',',Reloctype,')');}
  275. if CurrObjSec=nil then
  276. internalerror(200403072);
  277. objreloc:=nil;
  278. if assigned(p) then
  279. begin
  280. { real address of the symbol }
  281. symaddr:=p.address;
  282. objreloc:=TOmfRelocation.CreateSymbol(CurrObjSec.Size,p,Reloctype);
  283. CurrObjSec.ObjRelocations.Add(objreloc);
  284. inc(data,symaddr);
  285. end;
  286. CurrObjSec.write(data,len);
  287. end;
  288. {****************************************************************************
  289. TOmfObjOutput
  290. ****************************************************************************}
  291. procedure TOmfObjOutput.AddSegment(const name, segclass, ovlname: string;
  292. Alignment: TOmfSegmentAlignment; Combination: TOmfSegmentCombination;
  293. Use: TOmfSegmentUse; Size: aword);
  294. var
  295. s: TOmfRecord_SEGDEF;
  296. begin
  297. s:=TOmfRecord_SEGDEF.Create;
  298. Segments.Add(name,s);
  299. s.SegmentNameIndex:=LNames.Add(name);
  300. s.ClassNameIndex:=LNames.Add(segclass);
  301. s.OverlayNameIndex:=LNames.Add(ovlname);
  302. s.Alignment:=Alignment;
  303. s.Combination:=Combination;
  304. s.Use:=Use;
  305. s.SegmentLength:=Size;
  306. end;
  307. procedure TOmfObjOutput.AddGroup(const groupname: string; seglist: array of const);
  308. var
  309. g: TOmfRecord_GRPDEF;
  310. I: Integer;
  311. SegListStr: TSegmentList;
  312. begin
  313. g:=TOmfRecord_GRPDEF.Create;
  314. Groups.Add(groupname,g);
  315. g.GroupNameIndex:=LNames.Add(groupname);
  316. SetLength(SegListStr,Length(seglist));
  317. for I:=0 to High(seglist) do
  318. begin
  319. case seglist[I].VType of
  320. vtString:
  321. SegListStr[I]:=Segments.FindIndexOf(seglist[I].VString^);
  322. vtAnsiString:
  323. SegListStr[I]:=Segments.FindIndexOf(AnsiString(seglist[I].VAnsiString));
  324. vtWideString:
  325. SegListStr[I]:=Segments.FindIndexOf(AnsiString(WideString(seglist[I].VWideString)));
  326. vtUnicodeString:
  327. SegListStr[I]:=Segments.FindIndexOf(AnsiString(UnicodeString(seglist[I].VUnicodeString)));
  328. else
  329. internalerror(2015040402);
  330. end;
  331. end;
  332. g.SegmentList:=SegListStr;
  333. end;
  334. procedure TOmfObjOutput.WriteSections(Data: TObjData);
  335. var
  336. i:longint;
  337. sec:TObjSection;
  338. begin
  339. for i:=0 to Data.ObjSectionList.Count-1 do
  340. begin
  341. sec:=TObjSection(Data.ObjSectionList[i]);
  342. WriteSectionContentAndFixups(sec);
  343. end;
  344. end;
  345. procedure TOmfObjOutput.WriteSectionContentAndFixups(sec: TObjSection);
  346. const
  347. MaxChunkSize=$3fa;
  348. var
  349. RawRecord: TOmfRawRecord;
  350. ChunkStart,ChunkLen: DWord;
  351. ChunkFixupStart,ChunkFixupEnd: Integer;
  352. SegIndex: Integer;
  353. NextOfs: Integer;
  354. I: Integer;
  355. begin
  356. if (oso_data in sec.SecOptions) then
  357. begin
  358. if sec.Data=nil then
  359. internalerror(200403073);
  360. SegIndex:=Segments.FindIndexOf(sec.Name);
  361. RawRecord:=TOmfRawRecord.Create;
  362. sec.data.seek(0);
  363. ChunkFixupStart:=0;
  364. ChunkFixupEnd:=-1;
  365. ChunkStart:=0;
  366. ChunkLen:=Min(MaxChunkSize, sec.Data.size-ChunkStart);
  367. while ChunkLen>0 do
  368. begin
  369. { write LEDATA record }
  370. RawRecord.RecordType:=RT_LEDATA;
  371. NextOfs:=RawRecord.WriteIndexedRef(0,SegIndex);
  372. RawRecord.RawData[NextOfs]:=Byte(ChunkStart);
  373. RawRecord.RawData[NextOfs+1]:=Byte(ChunkStart shr 8);
  374. Inc(NextOfs,2);
  375. sec.data.read(RawRecord.RawData[NextOfs], ChunkLen);
  376. Inc(NextOfs, ChunkLen);
  377. RawRecord.RecordLength:=NextOfs+1;
  378. RawRecord.CalculateChecksumByte;
  379. RawRecord.WriteTo(FWriter);
  380. { write FIXUPP record }
  381. while (ChunkFixupEnd<(sec.ObjRelocations.Count-1)) and
  382. (TOmfRelocation(sec.ObjRelocations[ChunkFixupEnd+1]).OmfFixup.LocationOffset<(ChunkStart+ChunkLen)) do
  383. inc(ChunkFixupEnd);
  384. if ChunkFixupEnd>=ChunkFixupStart then
  385. begin
  386. RawRecord.RecordType:=RT_FIXUPP;
  387. NextOfs:=0;
  388. for I:=ChunkFixupStart to ChunkFixupEnd do
  389. begin
  390. TOmfRelocation(sec.ObjRelocations[I]).OmfFixup.DataRecordStartOffset:=ChunkStart;
  391. NextOfs:=TOmfRelocation(sec.ObjRelocations[I]).OmfFixup.WriteAt(RawRecord,NextOfs);
  392. end;
  393. RawRecord.RecordLength:=NextOfs+1;
  394. RawRecord.CalculateChecksumByte;
  395. RawRecord.WriteTo(FWriter);
  396. end;
  397. { prepare next chunk }
  398. Inc(ChunkStart, ChunkLen);
  399. ChunkLen:=Min(MaxChunkSize, sec.Data.size-ChunkStart);
  400. ChunkFixupStart:=ChunkFixupEnd+1;
  401. end;
  402. RawRecord.Free;
  403. end;
  404. end;
  405. procedure TOmfObjOutput.section_count_sections(p: TObject; arg: pointer);
  406. begin
  407. TOmfObjSection(p).index:=pinteger(arg)^;
  408. inc(pinteger(arg)^);
  409. end;
  410. function TOmfObjOutput.writeData(Data:TObjData):boolean;
  411. var
  412. RawRecord: TOmfRawRecord;
  413. Header: TOmfRecord_THEADR;
  414. Translator_COMENT: TOmfRecord_COMENT;
  415. LinkPassSeparator_COMENT: TOmfRecord_COMENT;
  416. LNamesRec: TOmfRecord_LNAMES;
  417. ModEnd: TOmfRecord_MODEND;
  418. I: Integer;
  419. SegDef: TOmfRecord_SEGDEF;
  420. GrpDef: TOmfRecord_GRPDEF;
  421. nsections: Integer;
  422. begin
  423. { calc amount of sections we have and set their index, starting with 1 }
  424. nsections:=1;
  425. data.ObjSectionList.ForEachCall(@section_count_sections,@nsections);
  426. { maximum amount of sections supported in the omf format is $7fff }
  427. if (nsections-1)>$7fff then
  428. internalerror(2015040701);
  429. { write header record }
  430. RawRecord:=TOmfRawRecord.Create;
  431. Header:=TOmfRecord_THEADR.Create;
  432. Header.ModuleName:=Data.Name;
  433. Header.EncodeTo(RawRecord);
  434. RawRecord.WriteTo(FWriter);
  435. Header.Free;
  436. { write translator COMENT header }
  437. Translator_COMENT:=TOmfRecord_COMENT.Create;
  438. Translator_COMENT.CommentClass:=CC_Translator;
  439. Translator_COMENT.CommentString:='FPC '+full_version_string+
  440. ' ['+date_string+'] for '+target_cpu_string+' - '+target_info.shortname;
  441. Translator_COMENT.EncodeTo(RawRecord);
  442. RawRecord.WriteTo(FWriter);
  443. Translator_COMENT.Free;
  444. LNames.Clear;
  445. LNames.Add(''); { insert an empty string, which has index 1 }
  446. for i:=0 to Data.ObjSectionList.Count-1 do
  447. with TOmfObjSection(Data.ObjSectionList[I]) do
  448. AddSegment(Name,ClassName,OverlayName,OmfAlignment,Combination,Use,Size);
  449. { if current_settings.x86memorymodel=mm_tiny then
  450. AddGroup('dgroup',['text','rodata','data','fpc','bss','heap'])
  451. else if current_settings.x86memorymodel in x86_near_data_models then
  452. AddGroup('dgroup',['rodata','data','fpc','bss','stack','heap'])
  453. else
  454. AddGroup('dgroup',['rodata','data','fpc','bss']);}
  455. { write LNAMES record(s) }
  456. LNamesRec:=TOmfRecord_LNAMES.Create;
  457. LNamesRec.Names:=LNames;
  458. while LNamesRec.NextIndex<=LNames.Count do
  459. begin
  460. LNamesRec.EncodeTo(RawRecord);
  461. RawRecord.WriteTo(FWriter);
  462. end;
  463. LNamesRec.Free;
  464. { write SEGDEF record(s) }
  465. for I:=1 to Segments.Count-1 do
  466. begin
  467. SegDef:=TOmfRecord_SEGDEF(Segments[I]);
  468. SegDef.EncodeTo(RawRecord);
  469. RawRecord.WriteTo(FWriter);
  470. end;
  471. { write GRPDEF record(s) }
  472. for I:=1 to Groups.Count-1 do
  473. begin
  474. GrpDef:=TOmfRecord_GRPDEF(Groups[I]);
  475. GrpDef.EncodeTo(RawRecord);
  476. RawRecord.WriteTo(FWriter);
  477. end;
  478. { write link pass separator }
  479. LinkPassSeparator_COMENT:=TOmfRecord_COMENT.Create;
  480. LinkPassSeparator_COMENT.CommentClass:=CC_LinkPassSeparator;
  481. LinkPassSeparator_COMENT.CommentString:=#1;
  482. LinkPassSeparator_COMENT.NoList:=True;
  483. LinkPassSeparator_COMENT.EncodeTo(RawRecord);
  484. RawRecord.WriteTo(FWriter);
  485. LinkPassSeparator_COMENT.Free;
  486. { write section content, interleaved with fixups }
  487. WriteSections(Data);
  488. { write MODEND record }
  489. ModEnd:=TOmfRecord_MODEND.Create;
  490. ModEnd.EncodeTo(RawRecord);
  491. RawRecord.WriteTo(FWriter);
  492. ModEnd.Free;
  493. RawRecord.Free;
  494. result:=true;
  495. end;
  496. constructor TOmfObjOutput.create(AWriter:TObjectWriter);
  497. begin
  498. inherited create(AWriter);
  499. cobjdata:=TOmfObjData;
  500. FLNames:=TOmfOrderedNameCollection.Create;
  501. FSegments:=TFPHashObjectList.Create;
  502. FSegments.Add('',nil);
  503. FGroups:=TFPHashObjectList.Create;
  504. FGroups.Add('',nil);
  505. end;
  506. destructor TOmfObjOutput.Destroy;
  507. begin
  508. FGroups.Free;
  509. FSegments.Free;
  510. FLNames.Free;
  511. inherited Destroy;
  512. end;
  513. {****************************************************************************
  514. TOmfAssembler
  515. ****************************************************************************}
  516. constructor TOmfAssembler.Create(smart:boolean);
  517. begin
  518. inherited Create(smart);
  519. CObjOutput:=TOmfObjOutput;
  520. end;
  521. {*****************************************************************************
  522. Initialize
  523. *****************************************************************************}
  524. {$ifdef i8086}
  525. const
  526. as_i8086_omf_info : tasminfo =
  527. (
  528. id : as_i8086_omf;
  529. idtxt : 'OMF';
  530. asmbin : '';
  531. asmcmd : '';
  532. supported_targets : [system_i8086_msdos];
  533. flags : [af_outputbinary,af_needar,af_no_debug];
  534. labelprefix : '..@';
  535. comment : '; ';
  536. dollarsign: '$';
  537. );
  538. {$endif i8086}
  539. initialization
  540. {$ifdef i8086}
  541. RegisterAssembler(as_i8086_omf_info,TOmfAssembler);
  542. {$endif i8086}
  543. end.