ogomf.pas 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034
  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. function GetGroupIndex(const groupname: string): Integer;
  39. public
  40. constructor CreateSection(ADataOffset:aword;aobjsec:TObjSection;Atyp:TObjRelocationType);
  41. destructor Destroy; override;
  42. procedure BuildOmfFixup;
  43. property OmfFixup: TOmfSubRecord_FIXUP read FOmfFixup;
  44. end;
  45. { TOmfObjSection }
  46. TOmfObjSection = class(TObjSection)
  47. private
  48. FClassName: string;
  49. FOverlayName: string;
  50. FCombination: TOmfSegmentCombination;
  51. FUse: TOmfSegmentUse;
  52. FPrimaryGroup: string;
  53. function GetOmfAlignment: TOmfSegmentAlignment;
  54. public
  55. constructor create(AList:TFPHashObjectList;const Aname:string;Aalign:shortint;Aoptions:TObjSectionOptions);override;
  56. property ClassName: string read FClassName;
  57. property OverlayName: string read FOverlayName;
  58. property OmfAlignment: TOmfSegmentAlignment read GetOmfAlignment;
  59. property Combination: TOmfSegmentCombination read FCombination;
  60. property Use: TOmfSegmentUse read FUse;
  61. property PrimaryGroup: string read FPrimaryGroup;
  62. end;
  63. { TOmfObjData }
  64. TOmfObjData = class(TObjData)
  65. private
  66. class function CodeSectionName(const aname:string): string;
  67. public
  68. constructor create(const n:string);override;
  69. function sectiontype2align(atype:TAsmSectiontype):shortint;override;
  70. function sectionname(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder):string;override;
  71. procedure writeReloc(Data:aint;len:aword;p:TObjSymbol;Reloctype:TObjRelocationType);override;
  72. end;
  73. { TOmfObjOutput }
  74. TOmfObjOutput = class(tObjOutput)
  75. private
  76. FLNames: TOmfOrderedNameCollection;
  77. FSegments: TFPHashObjectList;
  78. FGroups: TFPHashObjectList;
  79. procedure AddSegment(const name,segclass,ovlname: string;
  80. Alignment: TOmfSegmentAlignment; Combination: TOmfSegmentCombination;
  81. Use: TOmfSegmentUse; Size: aword);
  82. procedure AddGroup(const groupname: string; seglist: array of const);
  83. procedure AddGroup(const groupname: string; seglist: TSegmentList);
  84. procedure WriteSections(Data:TObjData);
  85. procedure WriteSectionContentAndFixups(sec: TObjSection);
  86. procedure section_count_sections(p:TObject;arg:pointer);
  87. procedure WritePUBDEFs(Data: TObjData);
  88. procedure WriteEXTDEFs(Data: TObjData);
  89. property LNames: TOmfOrderedNameCollection read FLNames;
  90. property Segments: TFPHashObjectList read FSegments;
  91. property Groups: TFPHashObjectList read FGroups;
  92. protected
  93. function writeData(Data:TObjData):boolean;override;
  94. public
  95. constructor create(AWriter:TObjectWriter);override;
  96. destructor Destroy;override;
  97. end;
  98. { TOmfObjInput }
  99. TOmfObjInput = class(TObjInput)
  100. private
  101. FRawRecord: TOmfRawRecord;
  102. public
  103. constructor create;override;
  104. destructor destroy;override;
  105. class function CanReadObjData(AReader:TObjectreader):boolean;override;
  106. function ReadObjData(AReader:TObjectreader;out objdata:TObjData):boolean;override;
  107. end;
  108. { TMZExeOutput }
  109. TMZExeOutput = class(TExeOutput)
  110. constructor create;override;
  111. end;
  112. TOmfAssembler = class(tinternalassembler)
  113. constructor create(smart:boolean);override;
  114. end;
  115. implementation
  116. uses
  117. SysUtils,
  118. cutils,verbose,globals,
  119. fmodule,aasmtai,aasmdata,
  120. ogmap,owomflib,
  121. version
  122. ;
  123. {****************************************************************************
  124. TOmfRelocation
  125. ****************************************************************************}
  126. function TOmfRelocation.GetGroupIndex(const groupname: string): Integer;
  127. begin
  128. if groupname='dgroup' then
  129. Result:=1
  130. else
  131. internalerror(2014040703);
  132. end;
  133. constructor TOmfRelocation.CreateSection(ADataOffset: aword; aobjsec: TObjSection; Atyp: TObjRelocationType);
  134. begin
  135. if not (Atyp in [RELOC_DGROUP,RELOC_DGROUPREL]) and not assigned(aobjsec) then
  136. internalerror(200603036);
  137. DataOffset:=ADataOffset;
  138. Symbol:=nil;
  139. OrgSize:=0;
  140. ObjSection:=aobjsec;
  141. ftype:=ord(Atyp);
  142. end;
  143. destructor TOmfRelocation.Destroy;
  144. begin
  145. FOmfFixup.Free;
  146. inherited Destroy;
  147. end;
  148. procedure TOmfRelocation.BuildOmfFixup;
  149. begin
  150. FreeAndNil(FOmfFixup);
  151. FOmfFixup:=TOmfSubRecord_FIXUP.Create;
  152. if ObjSection<>nil then
  153. begin
  154. FOmfFixup.LocationOffset:=DataOffset;
  155. if typ in [RELOC_ABSOLUTE,RELOC_RELATIVE] then
  156. FOmfFixup.LocationType:=fltOffset
  157. else if typ in [RELOC_SEG,RELOC_SEGREL] then
  158. FOmfFixup.LocationType:=fltBase
  159. else
  160. internalerror(2015041501);
  161. FOmfFixup.FrameDeterminedByThread:=False;
  162. FOmfFixup.TargetDeterminedByThread:=False;
  163. if typ in [RELOC_ABSOLUTE,RELOC_SEG] then
  164. FOmfFixup.Mode:=fmSegmentRelative
  165. else if typ in [RELOC_RELATIVE,RELOC_SEGREL] then
  166. FOmfFixup.Mode:=fmSelfRelative
  167. else
  168. internalerror(2015041401);
  169. if typ in [RELOC_ABSOLUTE,RELOC_RELATIVE] then
  170. begin
  171. FOmfFixup.TargetMethod:=ftmSegmentIndexNoDisp;
  172. FOmfFixup.TargetDatum:=ObjSection.Index;
  173. if TOmfObjSection(ObjSection).PrimaryGroup<>'' then
  174. begin
  175. FOmfFixup.FrameMethod:=ffmGroupIndex;
  176. FOmfFixup.FrameDatum:=GetGroupIndex(TOmfObjSection(ObjSection).PrimaryGroup);
  177. end
  178. else
  179. FOmfFixup.FrameMethod:=ffmTarget;
  180. end
  181. else
  182. begin
  183. FOmfFixup.FrameMethod:=ffmTarget;
  184. if TOmfObjSection(ObjSection).PrimaryGroup<>'' then
  185. begin
  186. FOmfFixup.TargetMethod:=ftmGroupIndexNoDisp;
  187. FOmfFixup.TargetDatum:=GetGroupIndex(TOmfObjSection(ObjSection).PrimaryGroup);
  188. end
  189. else
  190. begin
  191. FOmfFixup.TargetMethod:=ftmSegmentIndexNoDisp;
  192. FOmfFixup.TargetDatum:=ObjSection.Index;
  193. end;
  194. end;
  195. end
  196. else if symbol<>nil then
  197. begin
  198. FOmfFixup.LocationOffset:=DataOffset;
  199. if typ in [RELOC_ABSOLUTE,RELOC_RELATIVE] then
  200. FOmfFixup.LocationType:=fltOffset
  201. else if typ in [RELOC_SEG,RELOC_SEGREL] then
  202. FOmfFixup.LocationType:=fltBase
  203. else
  204. internalerror(2015041501);
  205. FOmfFixup.FrameDeterminedByThread:=False;
  206. FOmfFixup.TargetDeterminedByThread:=False;
  207. if typ in [RELOC_ABSOLUTE,RELOC_SEG] then
  208. FOmfFixup.Mode:=fmSegmentRelative
  209. else if typ in [RELOC_RELATIVE,RELOC_SEGREL] then
  210. FOmfFixup.Mode:=fmSelfRelative
  211. else
  212. internalerror(2015041401);
  213. FOmfFixup.TargetMethod:=ftmExternalIndexNoDisp;
  214. FOmfFixup.TargetDatum:=symbol.symidx;
  215. FOmfFixup.FrameMethod:=ffmTarget;
  216. end
  217. else if typ in [RELOC_DGROUP,RELOC_DGROUPREL] then
  218. begin
  219. FOmfFixup.LocationOffset:=DataOffset;
  220. FOmfFixup.LocationType:=fltBase;
  221. FOmfFixup.FrameDeterminedByThread:=False;
  222. FOmfFixup.TargetDeterminedByThread:=False;
  223. if typ=RELOC_DGROUP then
  224. FOmfFixup.Mode:=fmSegmentRelative
  225. else if typ=RELOC_DGROUPREL then
  226. FOmfFixup.Mode:=fmSelfRelative
  227. else
  228. internalerror(2015041401);
  229. FOmfFixup.FrameMethod:=ffmTarget;
  230. FOmfFixup.TargetMethod:=ftmGroupIndexNoDisp;
  231. FOmfFixup.TargetDatum:=GetGroupIndex('dgroup');
  232. end
  233. else
  234. internalerror(2015040702);
  235. end;
  236. {****************************************************************************
  237. TOmfObjSection
  238. ****************************************************************************}
  239. function TOmfObjSection.GetOmfAlignment: TOmfSegmentAlignment;
  240. begin
  241. case SecAlign of
  242. 1:
  243. result:=saRelocatableByteAligned;
  244. 2:
  245. result:=saRelocatableWordAligned;
  246. 4:
  247. result:=saRelocatableDWordAligned;
  248. 16:
  249. result:=saRelocatableParaAligned;
  250. else
  251. internalerror(2015041504);
  252. end;
  253. end;
  254. constructor TOmfObjSection.create(AList: TFPHashObjectList;
  255. const Aname: string; Aalign: shortint; Aoptions: TObjSectionOptions);
  256. var
  257. dgroup: Boolean;
  258. begin
  259. inherited create(AList, Aname, Aalign, Aoptions);
  260. FCombination:=scPublic;
  261. FUse:=suUse16;
  262. if oso_executable in Aoptions then
  263. begin
  264. FClassName:='code';
  265. dgroup:=(current_settings.x86memorymodel=mm_tiny);
  266. end
  267. else if Aname='stack' then
  268. begin
  269. FClassName:='stack';
  270. FCombination:=scStack;
  271. dgroup:=current_settings.x86memorymodel in (x86_near_data_models-[mm_tiny]);
  272. end
  273. else if Aname='heap' then
  274. begin
  275. FClassName:='heap';
  276. dgroup:=current_settings.x86memorymodel in x86_near_data_models;
  277. end
  278. else if Aname='bss' then
  279. begin
  280. FClassName:='bss';
  281. dgroup:=true;
  282. end
  283. else if Aname='data' then
  284. begin
  285. FClassName:='data';
  286. dgroup:=true;
  287. end
  288. else if (Aname='debug_frame') or
  289. (Aname='debug_info') or
  290. (Aname='debug_line') or
  291. (Aname='debug_abbrev') then
  292. begin
  293. FClassName:='DWARF';
  294. FUse:=suUse32;
  295. dgroup:=false;
  296. end
  297. else
  298. begin
  299. FClassName:='data';
  300. dgroup:=true;
  301. end;
  302. if dgroup then
  303. FPrimaryGroup:='dgroup'
  304. else
  305. FPrimaryGroup:='';
  306. end;
  307. {****************************************************************************
  308. TOmfObjData
  309. ****************************************************************************}
  310. class function TOmfObjData.CodeSectionName(const aname: string): string;
  311. begin
  312. {$ifdef i8086}
  313. if current_settings.x86memorymodel in x86_far_code_models then
  314. begin
  315. if cs_huge_code in current_settings.moduleswitches then
  316. result:=aname + '_TEXT'
  317. else
  318. result:=current_module.modulename^ + '_TEXT';
  319. end
  320. else
  321. {$endif}
  322. result:='text';
  323. end;
  324. constructor TOmfObjData.create(const n: string);
  325. begin
  326. inherited create(n);
  327. CObjSection:=TOmfObjSection;
  328. end;
  329. function TOmfObjData.sectiontype2align(atype: TAsmSectiontype): shortint;
  330. begin
  331. case atype of
  332. sec_stabstr:
  333. result:=1;
  334. sec_code:
  335. result:=1;
  336. sec_data,
  337. sec_rodata,
  338. sec_rodata_norel,
  339. sec_bss:
  340. result:=2;
  341. { For idata (at least idata2) it must be 4 bytes, because
  342. an entry is always (also in win64) 20 bytes and aligning
  343. on 8 bytes will insert 4 bytes between the entries resulting
  344. in a corrupt idata section.
  345. Same story with .pdata, it has 4-byte elements which should
  346. be packed without gaps. }
  347. sec_idata2,sec_idata4,sec_idata5,sec_idata6,sec_idata7,sec_pdata:
  348. result:=4;
  349. sec_debug_frame,sec_debug_info,sec_debug_line,sec_debug_abbrev:
  350. result:=4;
  351. sec_stack,
  352. sec_heap:
  353. result:=16;
  354. else
  355. result:=1;
  356. end;
  357. end;
  358. function TOmfObjData.sectionname(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder):string;
  359. const
  360. secnames : array[TAsmSectiontype] of string[length('__DATA, __datacoal_nt,coalesced')] = ('','',
  361. 'text',
  362. 'data',
  363. 'data',
  364. 'rodata',
  365. 'bss',
  366. 'tbss',
  367. 'pdata',
  368. 'text','data','data','data','data',
  369. 'stab',
  370. 'stabstr',
  371. 'idata2','idata4','idata5','idata6','idata7','edata',
  372. 'eh_frame',
  373. 'debug_frame','debug_info','debug_line','debug_abbrev',
  374. 'fpc',
  375. '',
  376. 'init',
  377. 'fini',
  378. 'objc_class',
  379. 'objc_meta_class',
  380. 'objc_cat_cls_meth',
  381. 'objc_cat_inst_meth',
  382. 'objc_protocol',
  383. 'objc_string_object',
  384. 'objc_cls_meth',
  385. 'objc_inst_meth',
  386. 'objc_cls_refs',
  387. 'objc_message_refs',
  388. 'objc_symbols',
  389. 'objc_category',
  390. 'objc_class_vars',
  391. 'objc_instance_vars',
  392. 'objc_module_info',
  393. 'objc_class_names',
  394. 'objc_meth_var_types',
  395. 'objc_meth_var_names',
  396. 'objc_selector_strs',
  397. 'objc_protocol_ext',
  398. 'objc_class_ext',
  399. 'objc_property',
  400. 'objc_image_info',
  401. 'objc_cstring_object',
  402. 'objc_sel_fixup',
  403. '__DATA,__objc_data',
  404. '__DATA,__objc_const',
  405. 'objc_superrefs',
  406. '__DATA, __datacoal_nt,coalesced',
  407. 'objc_classlist',
  408. 'objc_nlclasslist',
  409. 'objc_catlist',
  410. 'obcj_nlcatlist',
  411. 'objc_protolist',
  412. 'stack',
  413. 'heap'
  414. );
  415. begin
  416. if (atype=sec_user) then
  417. Result:=aname
  418. else if secnames[atype]='text' then
  419. Result:=CodeSectionName(aname)
  420. else
  421. Result:=secnames[atype];
  422. end;
  423. procedure TOmfObjData.writeReloc(Data:aint;len:aword;p:TObjSymbol;Reloctype:TObjRelocationType);
  424. var
  425. objreloc: TOmfRelocation;
  426. symaddr: AWord;
  427. begin
  428. { RELOC_FARPTR = RELOC_ABSOLUTE+RELOC_SEG }
  429. if Reloctype=RELOC_FARPTR then
  430. begin
  431. if len<>4 then
  432. internalerror(2015041502);
  433. writeReloc(Data,2,p,RELOC_ABSOLUTE);
  434. writeReloc(0,2,p,RELOC_SEG);
  435. exit;
  436. end;
  437. if CurrObjSec=nil then
  438. internalerror(200403072);
  439. objreloc:=nil;
  440. if assigned(p) then
  441. begin
  442. { real address of the symbol }
  443. symaddr:=p.address;
  444. if p.bind=AB_EXTERNAL then
  445. begin
  446. objreloc:=TOmfRelocation.CreateSymbol(CurrObjSec.Size,p,Reloctype);
  447. CurrObjSec.ObjRelocations.Add(objreloc);
  448. end
  449. { relative relocations within the same section can be calculated directly,
  450. without the need to emit a relocation entry }
  451. else if (p.objsection=CurrObjSec) and
  452. (p.bind<>AB_COMMON) and
  453. (Reloctype=RELOC_RELATIVE) then
  454. begin
  455. data:=data+symaddr-len-CurrObjSec.Size;
  456. end
  457. else
  458. begin
  459. objreloc:=TOmfRelocation.CreateSection(CurrObjSec.Size,p.objsection,Reloctype);
  460. CurrObjSec.ObjRelocations.Add(objreloc);
  461. if not (Reloctype in [RELOC_SEG,RELOC_SEGREL]) then
  462. inc(data,symaddr);
  463. end;
  464. end
  465. else if Reloctype in [RELOC_DGROUP,RELOC_DGROUPREL] then
  466. begin
  467. objreloc:=TOmfRelocation.CreateSection(CurrObjSec.Size,nil,Reloctype);
  468. CurrObjSec.ObjRelocations.Add(objreloc);
  469. end;
  470. CurrObjSec.write(data,len);
  471. end;
  472. {****************************************************************************
  473. TOmfObjOutput
  474. ****************************************************************************}
  475. procedure TOmfObjOutput.AddSegment(const name, segclass, ovlname: string;
  476. Alignment: TOmfSegmentAlignment; Combination: TOmfSegmentCombination;
  477. Use: TOmfSegmentUse; Size: aword);
  478. var
  479. s: TOmfRecord_SEGDEF;
  480. begin
  481. s:=TOmfRecord_SEGDEF.Create;
  482. Segments.Add(name,s);
  483. s.SegmentNameIndex:=LNames.Add(name);
  484. s.ClassNameIndex:=LNames.Add(segclass);
  485. s.OverlayNameIndex:=LNames.Add(ovlname);
  486. s.Alignment:=Alignment;
  487. s.Combination:=Combination;
  488. s.Use:=Use;
  489. s.SegmentLength:=Size;
  490. end;
  491. procedure TOmfObjOutput.AddGroup(const groupname: string; seglist: array of const);
  492. var
  493. g: TOmfRecord_GRPDEF;
  494. I: Integer;
  495. SegListStr: TSegmentList;
  496. begin
  497. g:=TOmfRecord_GRPDEF.Create;
  498. Groups.Add(groupname,g);
  499. g.GroupNameIndex:=LNames.Add(groupname);
  500. SetLength(SegListStr,Length(seglist));
  501. for I:=0 to High(seglist) do
  502. begin
  503. case seglist[I].VType of
  504. vtString:
  505. SegListStr[I]:=Segments.FindIndexOf(seglist[I].VString^);
  506. vtAnsiString:
  507. SegListStr[I]:=Segments.FindIndexOf(AnsiString(seglist[I].VAnsiString));
  508. vtWideString:
  509. SegListStr[I]:=Segments.FindIndexOf(AnsiString(WideString(seglist[I].VWideString)));
  510. vtUnicodeString:
  511. SegListStr[I]:=Segments.FindIndexOf(AnsiString(UnicodeString(seglist[I].VUnicodeString)));
  512. else
  513. internalerror(2015040402);
  514. end;
  515. end;
  516. g.SegmentList:=SegListStr;
  517. end;
  518. procedure TOmfObjOutput.AddGroup(const groupname: string; seglist: TSegmentList);
  519. var
  520. g: TOmfRecord_GRPDEF;
  521. begin
  522. g:=TOmfRecord_GRPDEF.Create;
  523. Groups.Add(groupname,g);
  524. g.GroupNameIndex:=LNames.Add(groupname);
  525. g.SegmentList:=Copy(seglist);
  526. end;
  527. procedure TOmfObjOutput.WriteSections(Data: TObjData);
  528. var
  529. i:longint;
  530. sec:TObjSection;
  531. begin
  532. for i:=0 to Data.ObjSectionList.Count-1 do
  533. begin
  534. sec:=TObjSection(Data.ObjSectionList[i]);
  535. WriteSectionContentAndFixups(sec);
  536. end;
  537. end;
  538. procedure TOmfObjOutput.WriteSectionContentAndFixups(sec: TObjSection);
  539. const
  540. MaxChunkSize=$3fa;
  541. var
  542. RawRecord: TOmfRawRecord;
  543. ChunkStart,ChunkLen: DWord;
  544. ChunkFixupStart,ChunkFixupEnd: Integer;
  545. SegIndex: Integer;
  546. NextOfs: Integer;
  547. I: Integer;
  548. begin
  549. if (oso_data in sec.SecOptions) then
  550. begin
  551. if sec.Data=nil then
  552. internalerror(200403073);
  553. for I:=0 to sec.ObjRelocations.Count-1 do
  554. TOmfRelocation(sec.ObjRelocations[I]).BuildOmfFixup;
  555. SegIndex:=Segments.FindIndexOf(sec.Name);
  556. RawRecord:=TOmfRawRecord.Create;
  557. sec.data.seek(0);
  558. ChunkFixupStart:=0;
  559. ChunkFixupEnd:=-1;
  560. ChunkStart:=0;
  561. ChunkLen:=Min(MaxChunkSize, sec.Data.size-ChunkStart);
  562. while ChunkLen>0 do
  563. begin
  564. { find last fixup in the chunk }
  565. while (ChunkFixupEnd<(sec.ObjRelocations.Count-1)) and
  566. (TOmfRelocation(sec.ObjRelocations[ChunkFixupEnd+1]).DataOffset<(ChunkStart+ChunkLen)) do
  567. inc(ChunkFixupEnd);
  568. { check if last chunk is crossing the chunk boundary, and trim ChunkLen if necessary }
  569. if (ChunkFixupEnd>=ChunkFixupStart) and
  570. ((TOmfRelocation(sec.ObjRelocations[ChunkFixupEnd]).DataOffset+
  571. TOmfRelocation(sec.ObjRelocations[ChunkFixupEnd]).OmfFixup.LocationSize)>(ChunkStart+ChunkLen)) then
  572. begin
  573. ChunkLen:=TOmfRelocation(sec.ObjRelocations[ChunkFixupEnd]).DataOffset-ChunkStart;
  574. Dec(ChunkFixupEnd);
  575. end;
  576. { write LEDATA record }
  577. RawRecord.RecordType:=RT_LEDATA;
  578. NextOfs:=RawRecord.WriteIndexedRef(0,SegIndex);
  579. RawRecord.RawData[NextOfs]:=Byte(ChunkStart);
  580. RawRecord.RawData[NextOfs+1]:=Byte(ChunkStart shr 8);
  581. Inc(NextOfs,2);
  582. sec.data.read(RawRecord.RawData[NextOfs], ChunkLen);
  583. Inc(NextOfs, ChunkLen);
  584. RawRecord.RecordLength:=NextOfs+1;
  585. RawRecord.CalculateChecksumByte;
  586. RawRecord.WriteTo(FWriter);
  587. { write FIXUPP record }
  588. if ChunkFixupEnd>=ChunkFixupStart then
  589. begin
  590. RawRecord.RecordType:=RT_FIXUPP;
  591. NextOfs:=0;
  592. for I:=ChunkFixupStart to ChunkFixupEnd do
  593. begin
  594. TOmfRelocation(sec.ObjRelocations[I]).OmfFixup.DataRecordStartOffset:=ChunkStart;
  595. NextOfs:=TOmfRelocation(sec.ObjRelocations[I]).OmfFixup.WriteAt(RawRecord,NextOfs);
  596. end;
  597. RawRecord.RecordLength:=NextOfs+1;
  598. RawRecord.CalculateChecksumByte;
  599. RawRecord.WriteTo(FWriter);
  600. end;
  601. { prepare next chunk }
  602. Inc(ChunkStart, ChunkLen);
  603. ChunkLen:=Min(MaxChunkSize, sec.Data.size-ChunkStart);
  604. ChunkFixupStart:=ChunkFixupEnd+1;
  605. end;
  606. RawRecord.Free;
  607. end;
  608. end;
  609. procedure TOmfObjOutput.section_count_sections(p: TObject; arg: pointer);
  610. begin
  611. TOmfObjSection(p).index:=pinteger(arg)^;
  612. inc(pinteger(arg)^);
  613. end;
  614. procedure TOmfObjOutput.WritePUBDEFs(Data: TObjData);
  615. var
  616. PubNamesForSection: array of TFPHashObjectList;
  617. i: Integer;
  618. objsym: TObjSymbol;
  619. PublicNameElem: TOmfPublicNameElement;
  620. RawRecord: TOmfRawRecord;
  621. PubDefRec: TOmfRecord_PUBDEF;
  622. PrimaryGroupName: string;
  623. begin
  624. RawRecord:=TOmfRawRecord.Create;
  625. SetLength(PubNamesForSection,Data.ObjSectionList.Count);
  626. for i:=0 to Data.ObjSectionList.Count-1 do
  627. PubNamesForSection[i]:=TFPHashObjectList.Create;
  628. for i:=0 to Data.ObjSymbolList.Count-1 do
  629. begin
  630. objsym:=TObjSymbol(Data.ObjSymbolList[i]);
  631. if objsym.bind=AB_GLOBAL then
  632. begin
  633. PublicNameElem:=TOmfPublicNameElement.Create(PubNamesForSection[objsym.objsection.index-1],objsym.Name);
  634. PublicNameElem.PublicOffset:=objsym.offset;
  635. end;
  636. end;
  637. for i:=0 to Data.ObjSectionList.Count-1 do
  638. if PubNamesForSection[i].Count>0 then
  639. begin
  640. PubDefRec:=TOmfRecord_PUBDEF.Create;
  641. PubDefRec.BaseSegmentIndex:=i+1;
  642. PrimaryGroupName:=TOmfObjSection(Data.ObjSectionList[i]).PrimaryGroup;
  643. if PrimaryGroupName<>'' then
  644. PubDefRec.BaseGroupIndex:=Groups.FindIndexOf(PrimaryGroupName)
  645. else
  646. PubDefRec.BaseGroupIndex:=0;
  647. PubDefRec.PublicNames:=PubNamesForSection[i];
  648. while PubDefRec.NextIndex<PubDefRec.PublicNames.Count do
  649. begin
  650. PubDefRec.EncodeTo(RawRecord);
  651. RawRecord.WriteTo(FWriter);
  652. end;
  653. PubDefRec.Free;
  654. end;
  655. for i:=0 to Data.ObjSectionList.Count-1 do
  656. FreeAndNil(PubNamesForSection[i]);
  657. RawRecord.Free;
  658. end;
  659. procedure TOmfObjOutput.WriteEXTDEFs(Data: TObjData);
  660. var
  661. ExtNames: TFPHashObjectList;
  662. RawRecord: TOmfRawRecord;
  663. i,idx: Integer;
  664. objsym: TObjSymbol;
  665. ExternalNameElem: TOmfExternalNameElement;
  666. ExtDefRec: TOmfRecord_EXTDEF;
  667. begin
  668. ExtNames:=TFPHashObjectList.Create;
  669. RawRecord:=TOmfRawRecord.Create;
  670. idx:=1;
  671. for i:=0 to Data.ObjSymbolList.Count-1 do
  672. begin
  673. objsym:=TObjSymbol(Data.ObjSymbolList[i]);
  674. if objsym.bind=AB_EXTERNAL then
  675. begin
  676. ExternalNameElem:=TOmfExternalNameElement.Create(ExtNames,objsym.Name);
  677. objsym.symidx:=idx;
  678. Inc(idx);
  679. end;
  680. end;
  681. if ExtNames.Count>0 then
  682. begin
  683. ExtDefRec:=TOmfRecord_EXTDEF.Create;
  684. ExtDefRec.ExternalNames:=ExtNames;
  685. while ExtDefRec.NextIndex<ExtDefRec.ExternalNames.Count do
  686. begin
  687. ExtDefRec.EncodeTo(RawRecord);
  688. RawRecord.WriteTo(FWriter);
  689. end;
  690. ExtDefRec.Free;
  691. end;
  692. ExtNames.Free;
  693. RawRecord.Free;
  694. end;
  695. function TOmfObjOutput.writeData(Data:TObjData):boolean;
  696. var
  697. RawRecord: TOmfRawRecord;
  698. Header: TOmfRecord_THEADR;
  699. Translator_COMENT: TOmfRecord_COMENT;
  700. LinkPassSeparator_COMENT: TOmfRecord_COMENT;
  701. LNamesRec: TOmfRecord_LNAMES;
  702. ModEnd: TOmfRecord_MODEND;
  703. I: Integer;
  704. SegDef: TOmfRecord_SEGDEF;
  705. GrpDef: TOmfRecord_GRPDEF;
  706. DGroupSegments: TSegmentList;
  707. nsections: Integer;
  708. begin
  709. { calc amount of sections we have and set their index, starting with 1 }
  710. nsections:=1;
  711. data.ObjSectionList.ForEachCall(@section_count_sections,@nsections);
  712. { maximum amount of sections supported in the omf format is $7fff }
  713. if (nsections-1)>$7fff then
  714. internalerror(2015040701);
  715. { write header record }
  716. RawRecord:=TOmfRawRecord.Create;
  717. Header:=TOmfRecord_THEADR.Create;
  718. Header.ModuleName:=Data.Name;
  719. Header.EncodeTo(RawRecord);
  720. RawRecord.WriteTo(FWriter);
  721. Header.Free;
  722. { write translator COMENT header }
  723. Translator_COMENT:=TOmfRecord_COMENT.Create;
  724. Translator_COMENT.CommentClass:=CC_Translator;
  725. Translator_COMENT.CommentString:='FPC '+full_version_string+
  726. ' ['+date_string+'] for '+target_cpu_string+' - '+target_info.shortname;
  727. Translator_COMENT.EncodeTo(RawRecord);
  728. RawRecord.WriteTo(FWriter);
  729. Translator_COMENT.Free;
  730. LNames.Clear;
  731. LNames.Add(''); { insert an empty string, which has index 1 }
  732. FSegments.Clear;
  733. FSegments.Add('',nil);
  734. FGroups.Clear;
  735. FGroups.Add('',nil);
  736. for i:=0 to Data.ObjSectionList.Count-1 do
  737. with TOmfObjSection(Data.ObjSectionList[I]) do
  738. AddSegment(Name,ClassName,OverlayName,OmfAlignment,Combination,Use,Size);
  739. { create group "dgroup" }
  740. SetLength(DGroupSegments,0);
  741. for i:=0 to Data.ObjSectionList.Count-1 do
  742. with TOmfObjSection(Data.ObjSectionList[I]) do
  743. if PrimaryGroup='dgroup' then
  744. begin
  745. SetLength(DGroupSegments,Length(DGroupSegments)+1);
  746. DGroupSegments[High(DGroupSegments)]:=index;
  747. end;
  748. AddGroup('dgroup',DGroupSegments);
  749. { write LNAMES record(s) }
  750. LNamesRec:=TOmfRecord_LNAMES.Create;
  751. LNamesRec.Names:=LNames;
  752. while LNamesRec.NextIndex<=LNames.Count do
  753. begin
  754. LNamesRec.EncodeTo(RawRecord);
  755. RawRecord.WriteTo(FWriter);
  756. end;
  757. LNamesRec.Free;
  758. { write SEGDEF record(s) }
  759. for I:=1 to Segments.Count-1 do
  760. begin
  761. SegDef:=TOmfRecord_SEGDEF(Segments[I]);
  762. SegDef.EncodeTo(RawRecord);
  763. RawRecord.WriteTo(FWriter);
  764. end;
  765. { write GRPDEF record(s) }
  766. for I:=1 to Groups.Count-1 do
  767. begin
  768. GrpDef:=TOmfRecord_GRPDEF(Groups[I]);
  769. GrpDef.EncodeTo(RawRecord);
  770. RawRecord.WriteTo(FWriter);
  771. end;
  772. { write PUBDEF record(s) }
  773. WritePUBDEFs(Data);
  774. { write EXTDEF record(s) }
  775. WriteEXTDEFs(Data);
  776. { write link pass separator }
  777. LinkPassSeparator_COMENT:=TOmfRecord_COMENT.Create;
  778. LinkPassSeparator_COMENT.CommentClass:=CC_LinkPassSeparator;
  779. LinkPassSeparator_COMENT.CommentString:=#1;
  780. LinkPassSeparator_COMENT.NoList:=True;
  781. LinkPassSeparator_COMENT.EncodeTo(RawRecord);
  782. RawRecord.WriteTo(FWriter);
  783. LinkPassSeparator_COMENT.Free;
  784. { write section content, interleaved with fixups }
  785. WriteSections(Data);
  786. { write MODEND record }
  787. ModEnd:=TOmfRecord_MODEND.Create;
  788. ModEnd.EncodeTo(RawRecord);
  789. RawRecord.WriteTo(FWriter);
  790. ModEnd.Free;
  791. RawRecord.Free;
  792. result:=true;
  793. end;
  794. constructor TOmfObjOutput.create(AWriter:TObjectWriter);
  795. begin
  796. inherited create(AWriter);
  797. cobjdata:=TOmfObjData;
  798. FLNames:=TOmfOrderedNameCollection.Create;
  799. FSegments:=TFPHashObjectList.Create;
  800. FSegments.Add('',nil);
  801. FGroups:=TFPHashObjectList.Create;
  802. FGroups.Add('',nil);
  803. end;
  804. destructor TOmfObjOutput.Destroy;
  805. begin
  806. FGroups.Free;
  807. FSegments.Free;
  808. FLNames.Free;
  809. inherited Destroy;
  810. end;
  811. {****************************************************************************
  812. TOmfObjInput
  813. ****************************************************************************}
  814. constructor TOmfObjInput.create;
  815. begin
  816. inherited create;
  817. cobjdata:=TOmfObjData;
  818. FRawRecord:=TOmfRawRecord.Create;
  819. end;
  820. destructor TOmfObjInput.destroy;
  821. begin
  822. FRawRecord.Free;
  823. inherited destroy;
  824. end;
  825. class function TOmfObjInput.CanReadObjData(AReader: TObjectreader): boolean;
  826. var
  827. b: Byte;
  828. begin
  829. result:=false;
  830. if AReader.Read(b,sizeof(b)) then
  831. begin
  832. if b=RT_THEADR then
  833. { TODO: check additional fields }
  834. result:=true;
  835. end;
  836. AReader.Seek(0);
  837. end;
  838. function TOmfObjInput.ReadObjData(AReader: TObjectreader; out objdata: TObjData): boolean;
  839. begin
  840. FReader:=AReader;
  841. InputFileName:=AReader.FileName;
  842. objdata:=CObjData.Create(InputFileName);
  843. result:=false;
  844. FRawRecord.ReadFrom(FReader);
  845. if not FRawRecord.VerifyChecksumByte then
  846. begin
  847. InputError('Invalid checksum in OMF record');
  848. exit;
  849. end;
  850. if FRawRecord.RecordType<>RT_THEADR then
  851. begin
  852. InputError('Can''t read OMF header');
  853. exit;
  854. end;
  855. repeat
  856. FRawRecord.ReadFrom(FReader);
  857. if not FRawRecord.VerifyChecksumByte then
  858. begin
  859. InputError('Invalid checksum in OMF record');
  860. exit;
  861. end;
  862. case FRawRecord.RecordType of
  863. RT_LNAMES:
  864. begin
  865. {todo}
  866. end;
  867. RT_SEGDEF,RT_SEGDEF32:
  868. begin
  869. {todo}
  870. end;
  871. RT_GRPDEF:
  872. begin
  873. {todo}
  874. end;
  875. RT_COMENT:
  876. begin
  877. {todo}
  878. end;
  879. RT_EXTDEF:
  880. begin
  881. {todo}
  882. end;
  883. RT_PUBDEF,RT_PUBDEF32:
  884. begin
  885. {todo}
  886. end;
  887. RT_LEDATA,RT_LEDATA32:
  888. begin
  889. {todo}
  890. end;
  891. RT_FIXUPP,RT_FIXUPP32:
  892. begin
  893. {todo}
  894. end;
  895. RT_MODEND,RT_MODEND32:
  896. begin
  897. {todo}
  898. end;
  899. else
  900. begin
  901. InputError('Unsupported OMF record type $'+HexStr(FRawRecord.RecordType,2));
  902. exit;
  903. end;
  904. end;
  905. until FRawRecord.RecordType in [RT_MODEND,RT_MODEND32];
  906. end;
  907. {****************************************************************************
  908. TMZExeOutput
  909. ****************************************************************************}
  910. constructor TMZExeOutput.create;
  911. begin
  912. inherited create;
  913. CObjData:=TOmfObjData;
  914. end;
  915. {****************************************************************************
  916. TOmfAssembler
  917. ****************************************************************************}
  918. constructor TOmfAssembler.Create(smart:boolean);
  919. begin
  920. inherited Create(smart);
  921. CObjOutput:=TOmfObjOutput;
  922. CInternalAr:=TOmfLibObjectWriter;
  923. end;
  924. {*****************************************************************************
  925. Initialize
  926. *****************************************************************************}
  927. {$ifdef i8086}
  928. const
  929. as_i8086_omf_info : tasminfo =
  930. (
  931. id : as_i8086_omf;
  932. idtxt : 'OMF';
  933. asmbin : '';
  934. asmcmd : '';
  935. supported_targets : [system_i8086_msdos];
  936. flags : [af_outputbinary,af_no_debug];
  937. labelprefix : '..@';
  938. comment : '; ';
  939. dollarsign: '$';
  940. );
  941. {$endif i8086}
  942. initialization
  943. {$ifdef i8086}
  944. RegisterAssembler(as_i8086_omf_info,TOmfAssembler);
  945. {$endif i8086}
  946. end.