ogomf.pas 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  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. { TOmfObjData }
  35. TOmfObjData = class(TObjData)
  36. private
  37. class function CodeSectionName(const aname:string): string;
  38. public
  39. function sectionname(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder):string;override;
  40. procedure writeReloc(Data:aint;len:aword;p:TObjSymbol;Reloctype:TObjRelocationType);override;
  41. end;
  42. { TOmfObjOutput }
  43. TOmfObjOutput = class(tObjOutput)
  44. private
  45. FLNames: TOmfOrderedNameCollection;
  46. FSegments: TFPHashObjectList;
  47. FGroups: TFPHashObjectList;
  48. procedure AddSegment(const name,segclass: string;
  49. Alignment: TOmfSegmentAlignment; Combination: TOmfSegmentCombination;
  50. Use: TOmfSegmentUse);
  51. procedure AddGroup(const groupname: string; seglist: array of const);
  52. procedure WriteSections(Data:TObjData);
  53. procedure WriteSectionContentAndFixups(sec: TObjSection);
  54. property LNames: TOmfOrderedNameCollection read FLNames;
  55. property Segments: TFPHashObjectList read FSegments;
  56. property Groups: TFPHashObjectList read FGroups;
  57. protected
  58. function writeData(Data:TObjData):boolean;override;
  59. public
  60. constructor create(AWriter:TObjectWriter);override;
  61. destructor Destroy;override;
  62. end;
  63. TOmfAssembler = class(tinternalassembler)
  64. constructor create(smart:boolean);override;
  65. end;
  66. implementation
  67. uses
  68. SysUtils,
  69. cutils,verbose,globals,
  70. fmodule,aasmtai,aasmdata,
  71. ogmap,
  72. version
  73. ;
  74. {****************************************************************************
  75. TOmfObjData
  76. ****************************************************************************}
  77. class function TOmfObjData.CodeSectionName(const aname: string): string;
  78. begin
  79. {$ifdef i8086}
  80. if current_settings.x86memorymodel in x86_far_code_models then
  81. begin
  82. if cs_huge_code in current_settings.moduleswitches then
  83. result:=aname + '_TEXT'
  84. else
  85. result:=current_module.modulename^ + '_TEXT';
  86. end
  87. else
  88. {$endif}
  89. result:='text';
  90. end;
  91. function TOmfObjData.sectionname(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder):string;
  92. const
  93. secnames : array[TAsmSectiontype] of string[length('__DATA, __datacoal_nt,coalesced')] = ('','',
  94. 'text',
  95. 'data',
  96. 'data',
  97. 'rodata',
  98. 'bss',
  99. 'tbss',
  100. 'pdata',
  101. 'text','data','data','data','data',
  102. 'stab',
  103. 'stabstr',
  104. 'idata2','idata4','idata5','idata6','idata7','edata',
  105. 'eh_frame',
  106. 'debug_frame','debug_info','debug_line','debug_abbrev',
  107. 'fpc',
  108. '',
  109. 'init',
  110. 'fini',
  111. 'objc_class',
  112. 'objc_meta_class',
  113. 'objc_cat_cls_meth',
  114. 'objc_cat_inst_meth',
  115. 'objc_protocol',
  116. 'objc_string_object',
  117. 'objc_cls_meth',
  118. 'objc_inst_meth',
  119. 'objc_cls_refs',
  120. 'objc_message_refs',
  121. 'objc_symbols',
  122. 'objc_category',
  123. 'objc_class_vars',
  124. 'objc_instance_vars',
  125. 'objc_module_info',
  126. 'objc_class_names',
  127. 'objc_meth_var_types',
  128. 'objc_meth_var_names',
  129. 'objc_selector_strs',
  130. 'objc_protocol_ext',
  131. 'objc_class_ext',
  132. 'objc_property',
  133. 'objc_image_info',
  134. 'objc_cstring_object',
  135. 'objc_sel_fixup',
  136. '__DATA,__objc_data',
  137. '__DATA,__objc_const',
  138. 'objc_superrefs',
  139. '__DATA, __datacoal_nt,coalesced',
  140. 'objc_classlist',
  141. 'objc_nlclasslist',
  142. 'objc_catlist',
  143. 'obcj_nlcatlist',
  144. 'objc_protolist',
  145. 'stack',
  146. 'heap'
  147. );
  148. begin
  149. if (atype=sec_user) then
  150. Result:=aname
  151. else if secnames[atype]='text' then
  152. Result:=CodeSectionName(aname)
  153. else
  154. Result:=secnames[atype];
  155. end;
  156. procedure TOmfObjData.writeReloc(Data:aint;len:aword;p:TObjSymbol;Reloctype:TObjRelocationType);
  157. begin
  158. end;
  159. {****************************************************************************
  160. TOmfObjOutput
  161. ****************************************************************************}
  162. procedure TOmfObjOutput.AddSegment(const name, segclass: string;
  163. Alignment: TOmfSegmentAlignment; Combination: TOmfSegmentCombination;
  164. Use: TOmfSegmentUse);
  165. var
  166. s: TOmfRecord_SEGDEF;
  167. begin
  168. s:=TOmfRecord_SEGDEF.Create;
  169. Segments.Add(name,s);
  170. s.SegmentNameIndex:=LNames.Add(name);
  171. s.ClassNameIndex:=LNames.Add(segclass);
  172. s.OverlayNameIndex:=1;
  173. s.Alignment:=Alignment;
  174. s.Combination:=Combination;
  175. s.Use:=Use;
  176. end;
  177. procedure TOmfObjOutput.AddGroup(const groupname: string; seglist: array of const);
  178. var
  179. g: TOmfRecord_GRPDEF;
  180. I: Integer;
  181. SegListStr: TSegmentList;
  182. begin
  183. g:=TOmfRecord_GRPDEF.Create;
  184. Groups.Add(groupname,g);
  185. g.GroupNameIndex:=LNames.Add(groupname);
  186. SetLength(SegListStr,Length(seglist));
  187. for I:=0 to High(seglist) do
  188. begin
  189. case seglist[I].VType of
  190. vtString:
  191. SegListStr[I]:=Segments.FindIndexOf(seglist[I].VString^);
  192. vtAnsiString:
  193. SegListStr[I]:=Segments.FindIndexOf(AnsiString(seglist[I].VAnsiString));
  194. vtWideString:
  195. SegListStr[I]:=Segments.FindIndexOf(WideString(seglist[I].VWideString));
  196. vtUnicodeString:
  197. SegListStr[I]:=Segments.FindIndexOf(UnicodeString(seglist[I].VUnicodeString));
  198. else
  199. internalerror(2015040402);
  200. end;
  201. end;
  202. g.SegmentList:=SegListStr;
  203. end;
  204. procedure TOmfObjOutput.WriteSections(Data: TObjData);
  205. var
  206. i:longint;
  207. sec:TObjSection;
  208. begin
  209. for i:=0 to Data.ObjSectionList.Count-1 do
  210. begin
  211. sec:=TObjSection(Data.ObjSectionList[i]);
  212. WriteSectionContentAndFixups(sec);
  213. end;
  214. end;
  215. procedure TOmfObjOutput.WriteSectionContentAndFixups(sec: TObjSection);
  216. const
  217. MaxChunkSize=$3fa;
  218. var
  219. RawRecord: TOmfRawRecord;
  220. ChunkStart,ChunkLen: DWord;
  221. SegIndex: Integer;
  222. NextOfs: Integer;
  223. begin
  224. if (oso_data in sec.SecOptions) then
  225. begin
  226. if sec.Data=nil then
  227. internalerror(200403073);
  228. SegIndex:=Segments.FindIndexOf(sec.Name);
  229. RawRecord:=TOmfRawRecord.Create;
  230. sec.data.seek(0);
  231. ChunkStart:=0;
  232. ChunkLen:=Min(MaxChunkSize, sec.Data.size-ChunkStart);
  233. while ChunkLen>0 do
  234. begin
  235. { write LEDATA record }
  236. RawRecord.RecordType:=RT_LEDATA;
  237. NextOfs:=RawRecord.WriteIndexedRef(0,SegIndex);
  238. RawRecord.RawData[NextOfs]:=Byte(ChunkStart);
  239. RawRecord.RawData[NextOfs+1]:=Byte(ChunkStart shr 8);
  240. Inc(NextOfs,2);
  241. sec.data.read(RawRecord.RawData[NextOfs], ChunkLen);
  242. Inc(NextOfs, ChunkLen);
  243. RawRecord.RecordLength:=NextOfs+1;
  244. RawRecord.CalculateChecksumByte;
  245. RawRecord.WriteTo(FWriter);
  246. { TODO: write fixups }
  247. { prepare next chunk }
  248. Inc(ChunkStart, ChunkLen);
  249. ChunkLen:=Min(1024, sec.Data.size-ChunkStart);
  250. end;
  251. RawRecord.Free;
  252. end;
  253. end;
  254. function TOmfObjOutput.writeData(Data:TObjData):boolean;
  255. var
  256. RawRecord: TOmfRawRecord;
  257. Header: TOmfRecord_THEADR;
  258. Translator_COMENT: TOmfRecord_COMENT;
  259. LinkPassSeparator_COMENT: TOmfRecord_COMENT;
  260. LNamesRec: TOmfRecord_LNAMES;
  261. ModEnd: TOmfRecord_MODEND;
  262. I: Integer;
  263. SegDef: TOmfRecord_SEGDEF;
  264. GrpDef: TOmfRecord_GRPDEF;
  265. begin
  266. { write header record }
  267. RawRecord:=TOmfRawRecord.Create;
  268. Header:=TOmfRecord_THEADR.Create;
  269. Header.ModuleName:=Data.Name;
  270. Header.EncodeTo(RawRecord);
  271. RawRecord.WriteTo(FWriter);
  272. Header.Free;
  273. { write translator COMENT header }
  274. Translator_COMENT:=TOmfRecord_COMENT.Create;
  275. Translator_COMENT.CommentClass:=CC_Translator;
  276. Translator_COMENT.CommentString:='FPC '+full_version_string+
  277. ' ['+date_string+'] for '+target_cpu_string+' - '+target_info.shortname;
  278. Translator_COMENT.EncodeTo(RawRecord);
  279. RawRecord.WriteTo(FWriter);
  280. Translator_COMENT.Free;
  281. LNames.Clear;
  282. LNames.Add(''); { insert an empty string, which has index 1 }
  283. if not (cs_huge_code in current_settings.moduleswitches) then
  284. AddSegment(TOmfObjData.CodeSectionName(current_module.modulename^),'code',saRelocatableByteAligned,scPublic,suUse16);
  285. AddSegment('rodata','data',saRelocatableByteAligned,scPublic,suUse16);
  286. AddSegment('data','data',saRelocatableWordAligned,scPublic,suUse16);
  287. AddSegment('fpc','data',saRelocatableByteAligned,scPublic,suUse16);
  288. AddSegment('bss','bss',saRelocatableByteAligned,scPublic,suUse16);
  289. AddSegment('stack','stack',saRelocatableParaAligned,scStack,suUse16);
  290. AddSegment('heap','heap',saRelocatableParaAligned,scPublic,suUse16);
  291. if current_settings.x86memorymodel=mm_tiny then
  292. AddGroup('dgroup',['text','rodata','data','fpc','bss','heap'])
  293. else if current_settings.x86memorymodel in x86_near_data_models then
  294. AddGroup('dgroup',['rodata','data','fpc','bss','stack','heap'])
  295. else
  296. AddGroup('dgroup',['rodata','data','fpc','bss']);
  297. { write LNAMES record(s) }
  298. LNamesRec:=TOmfRecord_LNAMES.Create;
  299. LNamesRec.Names:=LNames;
  300. while LNamesRec.NextIndex<=LNames.Count do
  301. begin
  302. LNamesRec.EncodeTo(RawRecord);
  303. RawRecord.WriteTo(FWriter);
  304. end;
  305. LNamesRec.Free;
  306. { write SEGDEF record(s) }
  307. for I:=1 to Segments.Count-1 do
  308. begin
  309. SegDef:=TOmfRecord_SEGDEF(Segments[I]);
  310. SegDef.EncodeTo(RawRecord);
  311. RawRecord.WriteTo(FWriter);
  312. end;
  313. { write GRPDEF record(s) }
  314. for I:=1 to Groups.Count-1 do
  315. begin
  316. GrpDef:=TOmfRecord_GRPDEF(Groups[I]);
  317. GrpDef.EncodeTo(RawRecord);
  318. RawRecord.WriteTo(FWriter);
  319. end;
  320. { write link pass separator }
  321. LinkPassSeparator_COMENT:=TOmfRecord_COMENT.Create;
  322. LinkPassSeparator_COMENT.CommentClass:=CC_LinkPassSeparator;
  323. LinkPassSeparator_COMENT.CommentString:=#1;
  324. LinkPassSeparator_COMENT.NoList:=True;
  325. LinkPassSeparator_COMENT.EncodeTo(RawRecord);
  326. RawRecord.WriteTo(FWriter);
  327. LinkPassSeparator_COMENT.Free;
  328. { write section content, interleaved with fixups }
  329. WriteSections(Data);
  330. { write MODEND record }
  331. ModEnd:=TOmfRecord_MODEND.Create;
  332. ModEnd.EncodeTo(RawRecord);
  333. RawRecord.WriteTo(FWriter);
  334. ModEnd.Free;
  335. RawRecord.Free;
  336. result:=true;
  337. end;
  338. constructor TOmfObjOutput.create(AWriter:TObjectWriter);
  339. begin
  340. inherited create(AWriter);
  341. cobjdata:=TOmfObjData;
  342. FLNames:=TOmfOrderedNameCollection.Create;
  343. FSegments:=TFPHashObjectList.Create;
  344. FSegments.Add('',nil);
  345. FGroups:=TFPHashObjectList.Create;
  346. FGroups.Add('',nil);
  347. end;
  348. destructor TOmfObjOutput.Destroy;
  349. begin
  350. FGroups.Free;
  351. FSegments.Free;
  352. FLNames.Free;
  353. inherited Destroy;
  354. end;
  355. {****************************************************************************
  356. TOmfAssembler
  357. ****************************************************************************}
  358. constructor TOmfAssembler.Create(smart:boolean);
  359. begin
  360. inherited Create(smart);
  361. CObjOutput:=TOmfObjOutput;
  362. end;
  363. {*****************************************************************************
  364. Initialize
  365. *****************************************************************************}
  366. {$ifdef i8086}
  367. const
  368. as_i8086_omf_info : tasminfo =
  369. (
  370. id : as_i8086_omf;
  371. idtxt : 'OMF';
  372. asmbin : '';
  373. asmcmd : '';
  374. supported_targets : [system_i8086_msdos];
  375. flags : [af_outputbinary,af_needar,af_no_debug];
  376. labelprefix : '..@';
  377. comment : '; ';
  378. dollarsign: '$';
  379. );
  380. {$endif i8086}
  381. initialization
  382. {$ifdef i8086}
  383. RegisterAssembler(as_i8086_omf_info,TOmfAssembler);
  384. {$endif i8086}
  385. end.