ogomf.pas 92 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538
  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. { TOmfObjSymbol }
  35. TOmfObjSymbol = class(TObjSymbol)
  36. public
  37. { string representation for the linker map file }
  38. function AddressStr(AImageBase: qword): string;override;
  39. end;
  40. { TOmfRelocation }
  41. TOmfRelocation = class(TObjRelocation)
  42. private
  43. FFrameGroup: string;
  44. FOmfFixup: TOmfSubRecord_FIXUP;
  45. function GetGroupIndex(const groupname: string): Integer;
  46. public
  47. constructor CreateSection(ADataOffset:aword;aobjsec:TObjSection;Atyp:TObjRelocationType);
  48. destructor Destroy; override;
  49. procedure BuildOmfFixup;
  50. property FrameGroup: string read FFrameGroup write FFrameGroup;
  51. property OmfFixup: TOmfSubRecord_FIXUP read FOmfFixup;
  52. end;
  53. TMZExeUnifiedLogicalSegment=class;
  54. { TOmfObjSection }
  55. TOmfObjSection = class(TObjSection)
  56. private
  57. FClassName: string;
  58. FOverlayName: string;
  59. FCombination: TOmfSegmentCombination;
  60. FUse: TOmfSegmentUse;
  61. FPrimaryGroup: string;
  62. FSortOrder: Integer;
  63. FMZExeUnifiedLogicalSegment: TMZExeUnifiedLogicalSegment;
  64. function GetOmfAlignment: TOmfSegmentAlignment;
  65. public
  66. constructor create(AList:TFPHashObjectList;const Aname:string;Aalign:shortint;Aoptions:TObjSectionOptions);override;
  67. function MemPosStr(AImageBase: qword): string;override;
  68. property ClassName: string read FClassName;
  69. property OverlayName: string read FOverlayName;
  70. property OmfAlignment: TOmfSegmentAlignment read GetOmfAlignment;
  71. property Combination: TOmfSegmentCombination read FCombination;
  72. property Use: TOmfSegmentUse read FUse;
  73. property PrimaryGroup: string read FPrimaryGroup;
  74. property SortOrder: Integer read FSortOrder write FSortOrder;
  75. property MZExeUnifiedLogicalSegment: TMZExeUnifiedLogicalSegment read FMZExeUnifiedLogicalSegment write FMZExeUnifiedLogicalSegment;
  76. end;
  77. { TOmfObjData }
  78. TOmfObjData = class(TObjData)
  79. private
  80. class function CodeSectionName(const aname:string): string;
  81. public
  82. constructor create(const n:string);override;
  83. function sectiontype2align(atype:TAsmSectiontype):shortint;override;
  84. function sectiontype2class(atype:TAsmSectiontype):string;
  85. function sectionname(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder):string;override;
  86. function createsection(atype:TAsmSectionType;const aname:string='';aorder:TAsmSectionOrder=secorder_default):TObjSection;override;
  87. procedure writeReloc(Data:aint;len:aword;p:TObjSymbol;Reloctype:TObjRelocationType);override;
  88. end;
  89. { TOmfObjOutput }
  90. TOmfObjOutput = class(tObjOutput)
  91. private
  92. FLNames: TOmfOrderedNameCollection;
  93. FSegments: TFPHashObjectList;
  94. FGroups: TFPHashObjectList;
  95. procedure AddSegment(const name,segclass,ovlname: string;
  96. Alignment: TOmfSegmentAlignment; Combination: TOmfSegmentCombination;
  97. Use: TOmfSegmentUse; Size: aword);
  98. procedure AddGroup(const groupname: string; seglist: array of const);
  99. procedure AddGroup(const groupname: string; seglist: TSegmentList);
  100. procedure WriteSections(Data:TObjData);
  101. procedure WriteSectionContentAndFixups(sec: TObjSection);
  102. procedure section_count_sections(p:TObject;arg:pointer);
  103. procedure WritePUBDEFs(Data: TObjData);
  104. procedure WriteEXTDEFs(Data: TObjData);
  105. property LNames: TOmfOrderedNameCollection read FLNames;
  106. property Segments: TFPHashObjectList read FSegments;
  107. property Groups: TFPHashObjectList read FGroups;
  108. protected
  109. function writeData(Data:TObjData):boolean;override;
  110. public
  111. constructor create(AWriter:TObjectWriter);override;
  112. destructor Destroy;override;
  113. end;
  114. { TOmfObjInput }
  115. TOmfObjInput = class(TObjInput)
  116. private
  117. FLNames: TOmfOrderedNameCollection;
  118. FExtDefs: TFPHashObjectList;
  119. FPubDefs: TFPHashObjectList;
  120. FRawRecord: TOmfRawRecord;
  121. FCaseSensitive: Boolean;
  122. function PeekNextRecordType: Byte;
  123. function ReadLNames(RawRec: TOmfRawRecord): Boolean;
  124. function ReadSegDef(RawRec: TOmfRawRecord; objdata:TObjData): Boolean;
  125. function ReadGrpDef(RawRec: TOmfRawRecord; objdata:TObjData): Boolean;
  126. function ReadExtDef(RawRec: TOmfRawRecord; objdata:TObjData): Boolean;
  127. function ReadPubDef(RawRec: TOmfRawRecord; objdata:TObjData): Boolean;
  128. function ReadModEnd(RawRec: TOmfRawRecord; objdata:TObjData): Boolean;
  129. function ReadLEDataAndFixups(RawRec: TOmfRawRecord; objdata:TObjData): Boolean;
  130. function ImportOmfFixup(objdata: TObjData; objsec: TOmfObjSection; Fixup: TOmfSubRecord_FIXUP): Boolean;
  131. property LNames: TOmfOrderedNameCollection read FLNames;
  132. property ExtDefs: TFPHashObjectList read FExtDefs;
  133. property PubDefs: TFPHashObjectList read FPubDefs;
  134. { Specifies whether we're case sensitive in regards to segment, class, overlay and group names.
  135. Symbols (in EXTDEF and PUBDEF records) are always case sensitive, regardless of the value of this property. }
  136. property CaseSensitive: Boolean read FCaseSensitive write FCaseSensitive;
  137. public
  138. constructor create;override;
  139. destructor destroy;override;
  140. class function CanReadObjData(AReader:TObjectreader):boolean;override;
  141. function ReadObjData(AReader:TObjectreader;out objdata:TObjData):boolean;override;
  142. end;
  143. { TMZExeRelocation }
  144. TMZExeRelocation = record
  145. offset: Word;
  146. segment: Word;
  147. end;
  148. TMZExeRelocations = array of TMZExeRelocation;
  149. TMZExeExtraHeaderData = array of Byte;
  150. { TMZExeHeader }
  151. TMZExeHeader = class
  152. private
  153. FChecksum: Word;
  154. FExtraHeaderData: TMZExeExtraHeaderData;
  155. FHeaderSizeAlignment: Integer;
  156. FInitialCS: Word;
  157. FInitialIP: Word;
  158. FInitialSP: Word;
  159. FInitialSS: Word;
  160. FLoadableImageSize: DWord;
  161. FMaxExtraParagraphs: Word;
  162. FMinExtraParagraphs: Word;
  163. FOverlayNumber: Word;
  164. FRelocations: TMZExeRelocations;
  165. procedure SetHeaderSizeAlignment(AValue: Integer);
  166. public
  167. constructor Create;
  168. procedure WriteTo(aWriter: TObjectWriter);
  169. procedure AddRelocation(aSegment,aOffset: Word);
  170. property HeaderSizeAlignment: Integer read FHeaderSizeAlignment write SetHeaderSizeAlignment; {default=16, must be multiple of 16}
  171. property Relocations: TMZExeRelocations read FRelocations write FRelocations;
  172. property ExtraHeaderData: TMZExeExtraHeaderData read FExtraHeaderData write FExtraHeaderData;
  173. property LoadableImageSize: DWord read FLoadableImageSize write FLoadableImageSize;
  174. property MinExtraParagraphs: Word read FMinExtraParagraphs write FMinExtraParagraphs;
  175. property MaxExtraParagraphs: Word read FMaxExtraParagraphs write FMaxExtraParagraphs;
  176. property InitialSS: Word read FInitialSS write FInitialSS;
  177. property InitialSP: Word read FInitialSP write FInitialSP;
  178. property Checksum: Word read FChecksum write FChecksum;
  179. property InitialIP: Word read FInitialIP write FInitialIP;
  180. property InitialCS: Word read FInitialCS write FInitialCS;
  181. property OverlayNumber: Word read FOverlayNumber write FOverlayNumber;
  182. end;
  183. { TMZExeSection }
  184. TMZExeSection=class(TExeSection)
  185. public
  186. procedure AddObjSection(objsec:TObjSection;ignoreprops:boolean=false);override;
  187. end;
  188. { TMZExeUnifiedLogicalSegment }
  189. TMZExeUnifiedLogicalSegment=class(TFPHashObject)
  190. private
  191. FObjSectionList: TFPObjectList;
  192. FSegName: TSymStr;
  193. FSegClass: TSymStr;
  194. FPrimaryGroup: string;
  195. public
  196. Size,
  197. MemPos,
  198. MemBasePos: qword;
  199. IsStack: Boolean;
  200. constructor create(HashObjectList:TFPHashObjectList;const s:TSymStr);
  201. destructor destroy;override;
  202. procedure AddObjSection(ObjSec: TOmfObjSection);
  203. procedure CalcMemPos;
  204. function MemPosStr:string;
  205. property ObjSectionList: TFPObjectList read FObjSectionList;
  206. property SegName: TSymStr read FSegName;
  207. property SegClass: TSymStr read FSegClass;
  208. property PrimaryGroup: string read FPrimaryGroup write FPrimaryGroup;
  209. end;
  210. { TMZExeUnifiedLogicalGroup }
  211. TMZExeUnifiedLogicalGroup=class(TFPHashObject)
  212. private
  213. FSegmentList: TFPHashObjectList;
  214. public
  215. Size,
  216. MemPos: qword;
  217. constructor create(HashObjectList:TFPHashObjectList;const s:TSymStr);
  218. destructor destroy;override;
  219. procedure CalcMemPos;
  220. function MemPosStr:string;
  221. procedure AddSegment(UniSeg: TMZExeUnifiedLogicalSegment);
  222. property SegmentList: TFPHashObjectList read FSegmentList;
  223. end;
  224. { TMZExeOutput }
  225. TMZExeOutput = class(TExeOutput)
  226. private
  227. FMZFlatContentSection: TMZExeSection;
  228. FExeUnifiedLogicalSegments: TFPHashObjectList;
  229. FExeUnifiedLogicalGroups: TFPHashObjectList;
  230. FHeader: TMZExeHeader;
  231. function GetMZFlatContentSection: TMZExeSection;
  232. procedure CalcExeUnifiedLogicalSegments;
  233. procedure CalcExeGroups;
  234. procedure CalcSegments_MemBasePos;
  235. procedure WriteMap_SegmentsAndGroups;
  236. procedure WriteMap_HeaderData;
  237. function FindStackSegment: TMZExeUnifiedLogicalSegment;
  238. procedure FillLoadableImageSize;
  239. procedure FillMinExtraParagraphs;
  240. procedure FillMaxExtraParagraphs;
  241. procedure FillStartAddress;
  242. procedure FillStackAddress;
  243. procedure FillHeaderData;
  244. function writeExe:boolean;
  245. function writeCom:boolean;
  246. property ExeUnifiedLogicalSegments: TFPHashObjectList read FExeUnifiedLogicalSegments;
  247. property ExeUnifiedLogicalGroups: TFPHashObjectList read FExeUnifiedLogicalGroups;
  248. property Header: TMZExeHeader read FHeader;
  249. protected
  250. procedure Load_Symbol(const aname:string);override;
  251. procedure DoRelocationFixup(objsec:TObjSection);override;
  252. procedure Order_ObjSectionList(ObjSectionList : TFPObjectList;const aPattern:string);override;
  253. procedure MemPos_EndExeSection;override;
  254. function writeData:boolean;override;
  255. public
  256. constructor create;override;
  257. destructor destroy;override;
  258. property MZFlatContentSection: TMZExeSection read GetMZFlatContentSection;
  259. end;
  260. TOmfAssembler = class(tinternalassembler)
  261. constructor create(smart:boolean);override;
  262. end;
  263. implementation
  264. uses
  265. SysUtils,
  266. cutils,verbose,globals,
  267. fmodule,aasmtai,aasmdata,
  268. ogmap,owomflib,
  269. version
  270. ;
  271. {****************************************************************************
  272. TOmfObjSymbol
  273. ****************************************************************************}
  274. function TOmfObjSymbol.AddressStr(AImageBase: qword): string;
  275. var
  276. base: qword;
  277. begin
  278. if assigned(TOmfObjSection(objsection).MZExeUnifiedLogicalSegment) then
  279. base:=TOmfObjSection(objsection).MZExeUnifiedLogicalSegment.MemBasePos
  280. else
  281. base:=(address shr 4) shl 4;
  282. Result:=HexStr(base shr 4,4)+':'+HexStr(address-base,4);
  283. end;
  284. {****************************************************************************
  285. TOmfRelocation
  286. ****************************************************************************}
  287. function TOmfRelocation.GetGroupIndex(const groupname: string): Integer;
  288. begin
  289. if groupname='DGROUP' then
  290. Result:=1
  291. else
  292. internalerror(2014040703);
  293. end;
  294. constructor TOmfRelocation.CreateSection(ADataOffset: aword; aobjsec: TObjSection; Atyp: TObjRelocationType);
  295. begin
  296. if not (Atyp in [RELOC_DGROUP,RELOC_DGROUPREL]) and not assigned(aobjsec) then
  297. internalerror(200603036);
  298. DataOffset:=ADataOffset;
  299. Symbol:=nil;
  300. OrgSize:=0;
  301. ObjSection:=aobjsec;
  302. ftype:=ord(Atyp);
  303. end;
  304. destructor TOmfRelocation.Destroy;
  305. begin
  306. FOmfFixup.Free;
  307. inherited Destroy;
  308. end;
  309. procedure TOmfRelocation.BuildOmfFixup;
  310. begin
  311. FreeAndNil(FOmfFixup);
  312. FOmfFixup:=TOmfSubRecord_FIXUP.Create;
  313. if ObjSection<>nil then
  314. begin
  315. FOmfFixup.LocationOffset:=DataOffset;
  316. if typ in [RELOC_ABSOLUTE,RELOC_RELATIVE] then
  317. FOmfFixup.LocationType:=fltOffset
  318. else if typ in [RELOC_SEG,RELOC_SEGREL] then
  319. FOmfFixup.LocationType:=fltBase
  320. else
  321. internalerror(2015041501);
  322. FOmfFixup.FrameDeterminedByThread:=False;
  323. FOmfFixup.TargetDeterminedByThread:=False;
  324. if typ in [RELOC_ABSOLUTE,RELOC_SEG] then
  325. FOmfFixup.Mode:=fmSegmentRelative
  326. else if typ in [RELOC_RELATIVE,RELOC_SEGREL] then
  327. FOmfFixup.Mode:=fmSelfRelative
  328. else
  329. internalerror(2015041401);
  330. if typ in [RELOC_ABSOLUTE,RELOC_RELATIVE] then
  331. begin
  332. FOmfFixup.TargetMethod:=ftmSegmentIndexNoDisp;
  333. FOmfFixup.TargetDatum:=ObjSection.Index;
  334. if TOmfObjSection(ObjSection).PrimaryGroup<>'' then
  335. begin
  336. FOmfFixup.FrameMethod:=ffmGroupIndex;
  337. FOmfFixup.FrameDatum:=GetGroupIndex(TOmfObjSection(ObjSection).PrimaryGroup);
  338. end
  339. else
  340. FOmfFixup.FrameMethod:=ffmTarget;
  341. end
  342. else
  343. begin
  344. FOmfFixup.FrameMethod:=ffmTarget;
  345. if TOmfObjSection(ObjSection).PrimaryGroup<>'' then
  346. begin
  347. FOmfFixup.TargetMethod:=ftmGroupIndexNoDisp;
  348. FOmfFixup.TargetDatum:=GetGroupIndex(TOmfObjSection(ObjSection).PrimaryGroup);
  349. end
  350. else
  351. begin
  352. FOmfFixup.TargetMethod:=ftmSegmentIndexNoDisp;
  353. FOmfFixup.TargetDatum:=ObjSection.Index;
  354. end;
  355. end;
  356. end
  357. else if symbol<>nil then
  358. begin
  359. FOmfFixup.LocationOffset:=DataOffset;
  360. if typ in [RELOC_ABSOLUTE,RELOC_RELATIVE] then
  361. FOmfFixup.LocationType:=fltOffset
  362. else if typ in [RELOC_SEG,RELOC_SEGREL] then
  363. FOmfFixup.LocationType:=fltBase
  364. else
  365. internalerror(2015041501);
  366. FOmfFixup.FrameDeterminedByThread:=False;
  367. FOmfFixup.TargetDeterminedByThread:=False;
  368. if typ in [RELOC_ABSOLUTE,RELOC_SEG] then
  369. FOmfFixup.Mode:=fmSegmentRelative
  370. else if typ in [RELOC_RELATIVE,RELOC_SEGREL] then
  371. FOmfFixup.Mode:=fmSelfRelative
  372. else
  373. internalerror(2015041401);
  374. FOmfFixup.TargetMethod:=ftmExternalIndexNoDisp;
  375. FOmfFixup.TargetDatum:=symbol.symidx;
  376. FOmfFixup.FrameMethod:=ffmTarget;
  377. end
  378. else if typ in [RELOC_DGROUP,RELOC_DGROUPREL] then
  379. begin
  380. FOmfFixup.LocationOffset:=DataOffset;
  381. FOmfFixup.LocationType:=fltBase;
  382. FOmfFixup.FrameDeterminedByThread:=False;
  383. FOmfFixup.TargetDeterminedByThread:=False;
  384. if typ=RELOC_DGROUP then
  385. FOmfFixup.Mode:=fmSegmentRelative
  386. else if typ=RELOC_DGROUPREL then
  387. FOmfFixup.Mode:=fmSelfRelative
  388. else
  389. internalerror(2015041401);
  390. FOmfFixup.FrameMethod:=ffmTarget;
  391. FOmfFixup.TargetMethod:=ftmGroupIndexNoDisp;
  392. FOmfFixup.TargetDatum:=GetGroupIndex('DGROUP');
  393. end
  394. else
  395. internalerror(2015040702);
  396. end;
  397. {****************************************************************************
  398. TOmfObjSection
  399. ****************************************************************************}
  400. function TOmfObjSection.GetOmfAlignment: TOmfSegmentAlignment;
  401. begin
  402. case SecAlign of
  403. 1:
  404. result:=saRelocatableByteAligned;
  405. 2:
  406. result:=saRelocatableWordAligned;
  407. 4:
  408. result:=saRelocatableDWordAligned;
  409. 16:
  410. result:=saRelocatableParaAligned;
  411. else
  412. internalerror(2015041504);
  413. end;
  414. end;
  415. constructor TOmfObjSection.create(AList: TFPHashObjectList;
  416. const Aname: string; Aalign: shortint; Aoptions: TObjSectionOptions);
  417. var
  418. dgroup: Boolean;
  419. begin
  420. inherited create(AList, Aname, Aalign, Aoptions);
  421. FCombination:=scPublic;
  422. FUse:=suUse16;
  423. if oso_executable in Aoptions then
  424. dgroup:=(current_settings.x86memorymodel=mm_tiny)
  425. else if Aname='stack' then
  426. begin
  427. FCombination:=scStack;
  428. dgroup:=current_settings.x86memorymodel in (x86_near_data_models-[mm_tiny]);
  429. end
  430. else if Aname='heap' then
  431. dgroup:=current_settings.x86memorymodel in x86_near_data_models
  432. else if Aname='bss' then
  433. dgroup:=true
  434. else if Aname='data' then
  435. dgroup:=true
  436. else if (Aname='debug_frame') or
  437. (Aname='debug_info') or
  438. (Aname='debug_line') or
  439. (Aname='debug_abbrev') then
  440. begin
  441. FUse:=suUse32;
  442. dgroup:=false;
  443. end
  444. else
  445. dgroup:=true;
  446. if dgroup then
  447. FPrimaryGroup:='DGROUP'
  448. else
  449. FPrimaryGroup:='';
  450. end;
  451. function TOmfObjSection.MemPosStr(AImageBase: qword): string;
  452. begin
  453. Result:=HexStr(MZExeUnifiedLogicalSegment.MemBasePos shr 4,4)+':'+
  454. HexStr(MemPos-MZExeUnifiedLogicalSegment.MemBasePos,4);
  455. end;
  456. {****************************************************************************
  457. TOmfObjData
  458. ****************************************************************************}
  459. class function TOmfObjData.CodeSectionName(const aname: string): string;
  460. begin
  461. {$ifdef i8086}
  462. if current_settings.x86memorymodel in x86_far_code_models then
  463. begin
  464. if cs_huge_code in current_settings.moduleswitches then
  465. result:=aname + '_TEXT'
  466. else
  467. result:=current_module.modulename^ + '_TEXT';
  468. end
  469. else
  470. {$endif}
  471. result:='_TEXT';
  472. end;
  473. constructor TOmfObjData.create(const n: string);
  474. begin
  475. inherited create(n);
  476. CObjSymbol:=TOmfObjSymbol;
  477. CObjSection:=TOmfObjSection;
  478. end;
  479. function TOmfObjData.sectiontype2align(atype: TAsmSectiontype): shortint;
  480. begin
  481. case atype of
  482. sec_stabstr:
  483. result:=1;
  484. sec_code:
  485. result:=1;
  486. sec_data,
  487. sec_rodata,
  488. sec_rodata_norel,
  489. sec_bss:
  490. result:=2;
  491. { For idata (at least idata2) it must be 4 bytes, because
  492. an entry is always (also in win64) 20 bytes and aligning
  493. on 8 bytes will insert 4 bytes between the entries resulting
  494. in a corrupt idata section.
  495. Same story with .pdata, it has 4-byte elements which should
  496. be packed without gaps. }
  497. sec_idata2,sec_idata4,sec_idata5,sec_idata6,sec_idata7,sec_pdata:
  498. result:=4;
  499. sec_debug_frame,sec_debug_info,sec_debug_line,sec_debug_abbrev:
  500. result:=4;
  501. sec_stack,
  502. sec_heap:
  503. result:=16;
  504. else
  505. result:=1;
  506. end;
  507. end;
  508. function TOmfObjData.sectiontype2class(atype: TAsmSectiontype): string;
  509. begin
  510. Result:=omf_segclass[atype];
  511. end;
  512. function TOmfObjData.sectionname(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder):string;
  513. begin
  514. if (atype=sec_user) then
  515. Result:=aname
  516. else if omf_secnames[atype]=omf_secnames[sec_code] then
  517. Result:=CodeSectionName(aname)
  518. else
  519. Result:=omf_secnames[atype];
  520. end;
  521. function TOmfObjData.createsection(atype: TAsmSectionType; const aname: string; aorder: TAsmSectionOrder): TObjSection;
  522. begin
  523. Result:=inherited createsection(atype, aname, aorder);
  524. TOmfObjSection(Result).FClassName:=sectiontype2class(atype);
  525. end;
  526. procedure TOmfObjData.writeReloc(Data:aint;len:aword;p:TObjSymbol;Reloctype:TObjRelocationType);
  527. var
  528. objreloc: TOmfRelocation;
  529. symaddr: AWord;
  530. begin
  531. { RELOC_FARPTR = RELOC_ABSOLUTE+RELOC_SEG }
  532. if Reloctype=RELOC_FARPTR then
  533. begin
  534. if len<>4 then
  535. internalerror(2015041502);
  536. writeReloc(Data,2,p,RELOC_ABSOLUTE);
  537. writeReloc(0,2,p,RELOC_SEG);
  538. exit;
  539. end;
  540. if CurrObjSec=nil then
  541. internalerror(200403072);
  542. objreloc:=nil;
  543. if assigned(p) then
  544. begin
  545. { real address of the symbol }
  546. symaddr:=p.address;
  547. if p.bind=AB_EXTERNAL then
  548. begin
  549. objreloc:=TOmfRelocation.CreateSymbol(CurrObjSec.Size,p,Reloctype);
  550. CurrObjSec.ObjRelocations.Add(objreloc);
  551. end
  552. { relative relocations within the same section can be calculated directly,
  553. without the need to emit a relocation entry }
  554. else if (p.objsection=CurrObjSec) and
  555. (p.bind<>AB_COMMON) and
  556. (Reloctype=RELOC_RELATIVE) then
  557. begin
  558. data:=data+symaddr-len-CurrObjSec.Size;
  559. end
  560. else
  561. begin
  562. objreloc:=TOmfRelocation.CreateSection(CurrObjSec.Size,p.objsection,Reloctype);
  563. CurrObjSec.ObjRelocations.Add(objreloc);
  564. if not (Reloctype in [RELOC_SEG,RELOC_SEGREL]) then
  565. inc(data,symaddr);
  566. end;
  567. end
  568. else if Reloctype in [RELOC_DGROUP,RELOC_DGROUPREL] then
  569. begin
  570. objreloc:=TOmfRelocation.CreateSection(CurrObjSec.Size,nil,Reloctype);
  571. CurrObjSec.ObjRelocations.Add(objreloc);
  572. end;
  573. CurrObjSec.write(data,len);
  574. end;
  575. {****************************************************************************
  576. TOmfObjOutput
  577. ****************************************************************************}
  578. procedure TOmfObjOutput.AddSegment(const name, segclass, ovlname: string;
  579. Alignment: TOmfSegmentAlignment; Combination: TOmfSegmentCombination;
  580. Use: TOmfSegmentUse; Size: aword);
  581. var
  582. s: TOmfRecord_SEGDEF;
  583. begin
  584. s:=TOmfRecord_SEGDEF.Create;
  585. Segments.Add(name,s);
  586. s.SegmentNameIndex:=LNames.Add(name);
  587. s.ClassNameIndex:=LNames.Add(segclass);
  588. s.OverlayNameIndex:=LNames.Add(ovlname);
  589. s.Alignment:=Alignment;
  590. s.Combination:=Combination;
  591. s.Use:=Use;
  592. s.SegmentLength:=Size;
  593. end;
  594. procedure TOmfObjOutput.AddGroup(const groupname: string; seglist: array of const);
  595. var
  596. g: TOmfRecord_GRPDEF;
  597. I: Integer;
  598. SegListStr: TSegmentList;
  599. begin
  600. g:=TOmfRecord_GRPDEF.Create;
  601. Groups.Add(groupname,g);
  602. g.GroupNameIndex:=LNames.Add(groupname);
  603. SetLength(SegListStr,Length(seglist));
  604. for I:=0 to High(seglist) do
  605. begin
  606. case seglist[I].VType of
  607. vtString:
  608. SegListStr[I]:=Segments.FindIndexOf(seglist[I].VString^);
  609. vtAnsiString:
  610. SegListStr[I]:=Segments.FindIndexOf(AnsiString(seglist[I].VAnsiString));
  611. vtWideString:
  612. SegListStr[I]:=Segments.FindIndexOf(AnsiString(WideString(seglist[I].VWideString)));
  613. vtUnicodeString:
  614. SegListStr[I]:=Segments.FindIndexOf(AnsiString(UnicodeString(seglist[I].VUnicodeString)));
  615. else
  616. internalerror(2015040402);
  617. end;
  618. end;
  619. g.SegmentList:=SegListStr;
  620. end;
  621. procedure TOmfObjOutput.AddGroup(const groupname: string; seglist: TSegmentList);
  622. var
  623. g: TOmfRecord_GRPDEF;
  624. begin
  625. g:=TOmfRecord_GRPDEF.Create;
  626. Groups.Add(groupname,g);
  627. g.GroupNameIndex:=LNames.Add(groupname);
  628. g.SegmentList:=Copy(seglist);
  629. end;
  630. procedure TOmfObjOutput.WriteSections(Data: TObjData);
  631. var
  632. i:longint;
  633. sec:TObjSection;
  634. begin
  635. for i:=0 to Data.ObjSectionList.Count-1 do
  636. begin
  637. sec:=TObjSection(Data.ObjSectionList[i]);
  638. WriteSectionContentAndFixups(sec);
  639. end;
  640. end;
  641. procedure TOmfObjOutput.WriteSectionContentAndFixups(sec: TObjSection);
  642. const
  643. MaxChunkSize=$3fa;
  644. var
  645. RawRecord: TOmfRawRecord;
  646. ChunkStart,ChunkLen: DWord;
  647. ChunkFixupStart,ChunkFixupEnd: Integer;
  648. SegIndex: Integer;
  649. NextOfs: Integer;
  650. I: Integer;
  651. begin
  652. if (oso_data in sec.SecOptions) then
  653. begin
  654. if sec.Data=nil then
  655. internalerror(200403073);
  656. for I:=0 to sec.ObjRelocations.Count-1 do
  657. TOmfRelocation(sec.ObjRelocations[I]).BuildOmfFixup;
  658. SegIndex:=Segments.FindIndexOf(sec.Name);
  659. RawRecord:=TOmfRawRecord.Create;
  660. sec.data.seek(0);
  661. ChunkFixupStart:=0;
  662. ChunkFixupEnd:=-1;
  663. ChunkStart:=0;
  664. ChunkLen:=Min(MaxChunkSize, sec.Data.size-ChunkStart);
  665. while ChunkLen>0 do
  666. begin
  667. { find last fixup in the chunk }
  668. while (ChunkFixupEnd<(sec.ObjRelocations.Count-1)) and
  669. (TOmfRelocation(sec.ObjRelocations[ChunkFixupEnd+1]).DataOffset<(ChunkStart+ChunkLen)) do
  670. inc(ChunkFixupEnd);
  671. { check if last chunk is crossing the chunk boundary, and trim ChunkLen if necessary }
  672. if (ChunkFixupEnd>=ChunkFixupStart) and
  673. ((TOmfRelocation(sec.ObjRelocations[ChunkFixupEnd]).DataOffset+
  674. TOmfRelocation(sec.ObjRelocations[ChunkFixupEnd]).OmfFixup.LocationSize)>(ChunkStart+ChunkLen)) then
  675. begin
  676. ChunkLen:=TOmfRelocation(sec.ObjRelocations[ChunkFixupEnd]).DataOffset-ChunkStart;
  677. Dec(ChunkFixupEnd);
  678. end;
  679. { write LEDATA record }
  680. RawRecord.RecordType:=RT_LEDATA;
  681. NextOfs:=RawRecord.WriteIndexedRef(0,SegIndex);
  682. RawRecord.RawData[NextOfs]:=Byte(ChunkStart);
  683. RawRecord.RawData[NextOfs+1]:=Byte(ChunkStart shr 8);
  684. Inc(NextOfs,2);
  685. sec.data.read(RawRecord.RawData[NextOfs], ChunkLen);
  686. Inc(NextOfs, ChunkLen);
  687. RawRecord.RecordLength:=NextOfs+1;
  688. RawRecord.CalculateChecksumByte;
  689. RawRecord.WriteTo(FWriter);
  690. { write FIXUPP record }
  691. if ChunkFixupEnd>=ChunkFixupStart then
  692. begin
  693. RawRecord.RecordType:=RT_FIXUPP;
  694. NextOfs:=0;
  695. for I:=ChunkFixupStart to ChunkFixupEnd do
  696. begin
  697. TOmfRelocation(sec.ObjRelocations[I]).OmfFixup.DataRecordStartOffset:=ChunkStart;
  698. NextOfs:=TOmfRelocation(sec.ObjRelocations[I]).OmfFixup.WriteAt(RawRecord,NextOfs);
  699. end;
  700. RawRecord.RecordLength:=NextOfs+1;
  701. RawRecord.CalculateChecksumByte;
  702. RawRecord.WriteTo(FWriter);
  703. end;
  704. { prepare next chunk }
  705. Inc(ChunkStart, ChunkLen);
  706. ChunkLen:=Min(MaxChunkSize, sec.Data.size-ChunkStart);
  707. ChunkFixupStart:=ChunkFixupEnd+1;
  708. end;
  709. RawRecord.Free;
  710. end;
  711. end;
  712. procedure TOmfObjOutput.section_count_sections(p: TObject; arg: pointer);
  713. begin
  714. TOmfObjSection(p).index:=pinteger(arg)^;
  715. inc(pinteger(arg)^);
  716. end;
  717. procedure TOmfObjOutput.WritePUBDEFs(Data: TObjData);
  718. var
  719. PubNamesForSection: array of TFPHashObjectList;
  720. i: Integer;
  721. objsym: TObjSymbol;
  722. PublicNameElem: TOmfPublicNameElement;
  723. RawRecord: TOmfRawRecord;
  724. PubDefRec: TOmfRecord_PUBDEF;
  725. PrimaryGroupName: string;
  726. begin
  727. RawRecord:=TOmfRawRecord.Create;
  728. SetLength(PubNamesForSection,Data.ObjSectionList.Count);
  729. for i:=0 to Data.ObjSectionList.Count-1 do
  730. PubNamesForSection[i]:=TFPHashObjectList.Create;
  731. for i:=0 to Data.ObjSymbolList.Count-1 do
  732. begin
  733. objsym:=TObjSymbol(Data.ObjSymbolList[i]);
  734. if objsym.bind=AB_GLOBAL then
  735. begin
  736. PublicNameElem:=TOmfPublicNameElement.Create(PubNamesForSection[objsym.objsection.index-1],objsym.Name);
  737. PublicNameElem.PublicOffset:=objsym.offset;
  738. end;
  739. end;
  740. for i:=0 to Data.ObjSectionList.Count-1 do
  741. if PubNamesForSection[i].Count>0 then
  742. begin
  743. PubDefRec:=TOmfRecord_PUBDEF.Create;
  744. PubDefRec.BaseSegmentIndex:=i+1;
  745. PrimaryGroupName:=TOmfObjSection(Data.ObjSectionList[i]).PrimaryGroup;
  746. if PrimaryGroupName<>'' then
  747. PubDefRec.BaseGroupIndex:=Groups.FindIndexOf(PrimaryGroupName)
  748. else
  749. PubDefRec.BaseGroupIndex:=0;
  750. PubDefRec.PublicNames:=PubNamesForSection[i];
  751. while PubDefRec.NextIndex<PubDefRec.PublicNames.Count do
  752. begin
  753. PubDefRec.EncodeTo(RawRecord);
  754. RawRecord.WriteTo(FWriter);
  755. end;
  756. PubDefRec.Free;
  757. end;
  758. for i:=0 to Data.ObjSectionList.Count-1 do
  759. FreeAndNil(PubNamesForSection[i]);
  760. RawRecord.Free;
  761. end;
  762. procedure TOmfObjOutput.WriteEXTDEFs(Data: TObjData);
  763. var
  764. ExtNames: TFPHashObjectList;
  765. RawRecord: TOmfRawRecord;
  766. i,idx: Integer;
  767. objsym: TObjSymbol;
  768. ExternalNameElem: TOmfExternalNameElement;
  769. ExtDefRec: TOmfRecord_EXTDEF;
  770. begin
  771. ExtNames:=TFPHashObjectList.Create;
  772. RawRecord:=TOmfRawRecord.Create;
  773. idx:=1;
  774. for i:=0 to Data.ObjSymbolList.Count-1 do
  775. begin
  776. objsym:=TObjSymbol(Data.ObjSymbolList[i]);
  777. if objsym.bind=AB_EXTERNAL then
  778. begin
  779. ExternalNameElem:=TOmfExternalNameElement.Create(ExtNames,objsym.Name);
  780. objsym.symidx:=idx;
  781. Inc(idx);
  782. end;
  783. end;
  784. if ExtNames.Count>0 then
  785. begin
  786. ExtDefRec:=TOmfRecord_EXTDEF.Create;
  787. ExtDefRec.ExternalNames:=ExtNames;
  788. while ExtDefRec.NextIndex<ExtDefRec.ExternalNames.Count do
  789. begin
  790. ExtDefRec.EncodeTo(RawRecord);
  791. RawRecord.WriteTo(FWriter);
  792. end;
  793. ExtDefRec.Free;
  794. end;
  795. ExtNames.Free;
  796. RawRecord.Free;
  797. end;
  798. function TOmfObjOutput.writeData(Data:TObjData):boolean;
  799. var
  800. RawRecord: TOmfRawRecord;
  801. Header: TOmfRecord_THEADR;
  802. Translator_COMENT: TOmfRecord_COMENT;
  803. LinkPassSeparator_COMENT: TOmfRecord_COMENT;
  804. LNamesRec: TOmfRecord_LNAMES;
  805. ModEnd: TOmfRecord_MODEND;
  806. I: Integer;
  807. SegDef: TOmfRecord_SEGDEF;
  808. GrpDef: TOmfRecord_GRPDEF;
  809. DGroupSegments: TSegmentList;
  810. nsections: Integer;
  811. begin
  812. { calc amount of sections we have and set their index, starting with 1 }
  813. nsections:=1;
  814. data.ObjSectionList.ForEachCall(@section_count_sections,@nsections);
  815. { maximum amount of sections supported in the omf format is $7fff }
  816. if (nsections-1)>$7fff then
  817. internalerror(2015040701);
  818. { write header record }
  819. RawRecord:=TOmfRawRecord.Create;
  820. Header:=TOmfRecord_THEADR.Create;
  821. Header.ModuleName:=Data.Name;
  822. Header.EncodeTo(RawRecord);
  823. RawRecord.WriteTo(FWriter);
  824. Header.Free;
  825. { write translator COMENT header }
  826. Translator_COMENT:=TOmfRecord_COMENT.Create;
  827. Translator_COMENT.CommentClass:=CC_Translator;
  828. Translator_COMENT.CommentString:='FPC '+full_version_string+
  829. ' ['+date_string+'] for '+target_cpu_string+' - '+target_info.shortname;
  830. Translator_COMENT.EncodeTo(RawRecord);
  831. RawRecord.WriteTo(FWriter);
  832. Translator_COMENT.Free;
  833. LNames.Clear;
  834. LNames.Add(''); { insert an empty string, which has index 1 }
  835. FSegments.Clear;
  836. FSegments.Add('',nil);
  837. FGroups.Clear;
  838. FGroups.Add('',nil);
  839. for i:=0 to Data.ObjSectionList.Count-1 do
  840. with TOmfObjSection(Data.ObjSectionList[I]) do
  841. AddSegment(Name,ClassName,OverlayName,OmfAlignment,Combination,Use,Size);
  842. { create group "DGROUP" }
  843. SetLength(DGroupSegments,0);
  844. for i:=0 to Data.ObjSectionList.Count-1 do
  845. with TOmfObjSection(Data.ObjSectionList[I]) do
  846. if PrimaryGroup='DGROUP' then
  847. begin
  848. SetLength(DGroupSegments,Length(DGroupSegments)+1);
  849. DGroupSegments[High(DGroupSegments)]:=index;
  850. end;
  851. AddGroup('DGROUP',DGroupSegments);
  852. { write LNAMES record(s) }
  853. LNamesRec:=TOmfRecord_LNAMES.Create;
  854. LNamesRec.Names:=LNames;
  855. while LNamesRec.NextIndex<=LNames.Count do
  856. begin
  857. LNamesRec.EncodeTo(RawRecord);
  858. RawRecord.WriteTo(FWriter);
  859. end;
  860. LNamesRec.Free;
  861. { write SEGDEF record(s) }
  862. for I:=1 to Segments.Count-1 do
  863. begin
  864. SegDef:=TOmfRecord_SEGDEF(Segments[I]);
  865. SegDef.EncodeTo(RawRecord);
  866. RawRecord.WriteTo(FWriter);
  867. end;
  868. { write GRPDEF record(s) }
  869. for I:=1 to Groups.Count-1 do
  870. begin
  871. GrpDef:=TOmfRecord_GRPDEF(Groups[I]);
  872. GrpDef.EncodeTo(RawRecord);
  873. RawRecord.WriteTo(FWriter);
  874. end;
  875. { write PUBDEF record(s) }
  876. WritePUBDEFs(Data);
  877. { write EXTDEF record(s) }
  878. WriteEXTDEFs(Data);
  879. { write link pass separator }
  880. LinkPassSeparator_COMENT:=TOmfRecord_COMENT.Create;
  881. LinkPassSeparator_COMENT.CommentClass:=CC_LinkPassSeparator;
  882. LinkPassSeparator_COMENT.CommentString:=#1;
  883. LinkPassSeparator_COMENT.NoList:=True;
  884. LinkPassSeparator_COMENT.EncodeTo(RawRecord);
  885. RawRecord.WriteTo(FWriter);
  886. LinkPassSeparator_COMENT.Free;
  887. { write section content, interleaved with fixups }
  888. WriteSections(Data);
  889. { write MODEND record }
  890. ModEnd:=TOmfRecord_MODEND.Create;
  891. ModEnd.EncodeTo(RawRecord);
  892. RawRecord.WriteTo(FWriter);
  893. ModEnd.Free;
  894. RawRecord.Free;
  895. result:=true;
  896. end;
  897. constructor TOmfObjOutput.create(AWriter:TObjectWriter);
  898. begin
  899. inherited create(AWriter);
  900. cobjdata:=TOmfObjData;
  901. FLNames:=TOmfOrderedNameCollection.Create;
  902. FSegments:=TFPHashObjectList.Create;
  903. FSegments.Add('',nil);
  904. FGroups:=TFPHashObjectList.Create;
  905. FGroups.Add('',nil);
  906. end;
  907. destructor TOmfObjOutput.Destroy;
  908. begin
  909. FGroups.Free;
  910. FSegments.Free;
  911. FLNames.Free;
  912. inherited Destroy;
  913. end;
  914. {****************************************************************************
  915. TOmfObjInput
  916. ****************************************************************************}
  917. function TOmfObjInput.PeekNextRecordType: Byte;
  918. var
  919. OldPos: LongInt;
  920. begin
  921. OldPos:=FReader.Pos;
  922. if not FReader.read(Result, 1) then
  923. begin
  924. InputError('Unexpected end of file');
  925. Result:=0;
  926. exit;
  927. end;
  928. FReader.seek(OldPos);
  929. end;
  930. function TOmfObjInput.ReadLNames(RawRec: TOmfRawRecord): Boolean;
  931. var
  932. LNamesRec: TOmfRecord_LNAMES;
  933. begin
  934. Result:=False;
  935. LNamesRec:=TOmfRecord_LNAMES.Create;
  936. LNamesRec.Names:=LNames;
  937. LNamesRec.DecodeFrom(RawRec);
  938. LNamesRec.Free;
  939. Result:=True;
  940. end;
  941. function TOmfObjInput.ReadSegDef(RawRec: TOmfRawRecord; objdata: TObjData): Boolean;
  942. var
  943. SegDefRec: TOmfRecord_SEGDEF;
  944. SegmentName,SegClassName,OverlayName: string;
  945. SecAlign: ShortInt;
  946. secoptions: TObjSectionOptions;
  947. objsec: TOmfObjSection;
  948. begin
  949. Result:=False;
  950. SegDefRec:=TOmfRecord_SEGDEF.Create;
  951. SegDefRec.DecodeFrom(RawRec);
  952. if (SegDefRec.SegmentNameIndex<1) or (SegDefRec.SegmentNameIndex>LNames.Count) then
  953. begin
  954. InputError('Segment name index out of range');
  955. SegDefRec.Free;
  956. exit;
  957. end;
  958. SegmentName:=LNames[SegDefRec.SegmentNameIndex];
  959. if (SegDefRec.ClassNameIndex<1) or (SegDefRec.ClassNameIndex>LNames.Count) then
  960. begin
  961. InputError('Segment class name index out of range');
  962. SegDefRec.Free;
  963. exit;
  964. end;
  965. SegClassName:=LNames[SegDefRec.ClassNameIndex];
  966. if (SegDefRec.OverlayNameIndex<1) or (SegDefRec.OverlayNameIndex>LNames.Count) then
  967. begin
  968. InputError('Segment overlay name index out of range');
  969. SegDefRec.Free;
  970. exit;
  971. end;
  972. OverlayName:=LNames[SegDefRec.OverlayNameIndex];
  973. SecAlign:=1; // otherwise warning prohibits compilation
  974. case SegDefRec.Alignment of
  975. saRelocatableByteAligned:
  976. SecAlign:=1;
  977. saRelocatableWordAligned:
  978. SecAlign:=2;
  979. saRelocatableParaAligned:
  980. SecAlign:=16;
  981. saRelocatableDWordAligned:
  982. SecAlign:=4;
  983. saRelocatablePageAligned:
  984. begin
  985. InputError('Page segment alignment not supported');
  986. SegDefRec.Free;
  987. exit;
  988. end;
  989. saAbsolute:
  990. begin
  991. InputError('Absolute segment alignment not supported');
  992. SegDefRec.Free;
  993. exit;
  994. end;
  995. saNotSupported,
  996. saNotDefined:
  997. begin
  998. InputError('Invalid (unsupported/undefined) OMF segment alignment');
  999. SegDefRec.Free;
  1000. exit;
  1001. end;
  1002. end;
  1003. if not CaseSensitive then
  1004. begin
  1005. SegmentName:=UpCase(SegmentName);
  1006. SegClassName:=UpCase(SegClassName);
  1007. OverlayName:=UpCase(OverlayName);
  1008. end;
  1009. secoptions:=[];
  1010. objsec:=TOmfObjSection(objdata.createsection(SegmentName+'||'+SegClassName,SecAlign,secoptions,false));
  1011. objsec.FClassName:=SegClassName;
  1012. objsec.FOverlayName:=OverlayName;
  1013. objsec.FCombination:=SegDefRec.Combination;
  1014. objsec.FUse:=SegDefRec.Use;
  1015. if SegDefRec.SegmentLength>High(objsec.Size) then
  1016. begin
  1017. InputError('Segment too large');
  1018. SegDefRec.Free;
  1019. exit;
  1020. end;
  1021. objsec.Size:=SegDefRec.SegmentLength;
  1022. if (SegClassName='HEAP') or
  1023. (SegClassName='STACK') or (SegDefRec.Combination=scStack) or
  1024. (SegClassName='BEGDATA') or
  1025. (SegmentName='FPC') then
  1026. objsec.SecOptions:=objsec.SecOptions+[oso_keep];
  1027. SegDefRec.Free;
  1028. Result:=True;
  1029. end;
  1030. function TOmfObjInput.ReadGrpDef(RawRec: TOmfRawRecord; objdata: TObjData): Boolean;
  1031. var
  1032. GrpDefRec: TOmfRecord_GRPDEF;
  1033. GroupName: string;
  1034. SecGroup: TObjSectionGroup;
  1035. i,SegIndex: Integer;
  1036. begin
  1037. Result:=False;
  1038. GrpDefRec:=TOmfRecord_GRPDEF.Create;
  1039. GrpDefRec.DecodeFrom(RawRec);
  1040. if (GrpDefRec.GroupNameIndex<1) or (GrpDefRec.GroupNameIndex>LNames.Count) then
  1041. begin
  1042. InputError('Group name index out of range');
  1043. GrpDefRec.Free;
  1044. exit;
  1045. end;
  1046. GroupName:=LNames[GrpDefRec.GroupNameIndex];
  1047. if not CaseSensitive then
  1048. GroupName:=UpCase(GroupName);
  1049. SecGroup:=objdata.createsectiongroup(GroupName);
  1050. SetLength(SecGroup.members,Length(GrpDefRec.SegmentList));
  1051. for i:=0 to Length(GrpDefRec.SegmentList)-1 do
  1052. begin
  1053. SegIndex:=GrpDefRec.SegmentList[i];
  1054. if (SegIndex<1) or (SegIndex>objdata.ObjSectionList.Count) then
  1055. begin
  1056. InputError('Segment name index out of range in group definition');
  1057. GrpDefRec.Free;
  1058. exit;
  1059. end;
  1060. SecGroup.members[i]:=TOmfObjSection(objdata.ObjSectionList[SegIndex-1]);
  1061. end;
  1062. GrpDefRec.Free;
  1063. Result:=True;
  1064. end;
  1065. function TOmfObjInput.ReadExtDef(RawRec: TOmfRawRecord; objdata: TObjData): Boolean;
  1066. var
  1067. ExtDefRec: TOmfRecord_EXTDEF;
  1068. ExtDefElem: TOmfExternalNameElement;
  1069. OldCount,NewCount,i: Integer;
  1070. objsym: TObjSymbol;
  1071. begin
  1072. Result:=False;
  1073. ExtDefRec:=TOmfRecord_EXTDEF.Create;
  1074. ExtDefRec.ExternalNames:=ExtDefs;
  1075. OldCount:=ExtDefs.Count;
  1076. ExtDefRec.DecodeFrom(RawRec);
  1077. NewCount:=ExtDefs.Count;
  1078. for i:=OldCount to NewCount-1 do
  1079. begin
  1080. ExtDefElem:=TOmfExternalNameElement(ExtDefs[i]);
  1081. objsym:=objdata.CreateSymbol(ExtDefElem.Name);
  1082. objsym.bind:=AB_EXTERNAL;
  1083. objsym.typ:=AT_FUNCTION;
  1084. objsym.objsection:=nil;
  1085. objsym.offset:=0;
  1086. objsym.size:=0;
  1087. end;
  1088. ExtDefRec.Free;
  1089. Result:=True;
  1090. end;
  1091. function TOmfObjInput.ReadPubDef(RawRec: TOmfRawRecord; objdata:TObjData): Boolean;
  1092. var
  1093. PubDefRec: TOmfRecord_PUBDEF;
  1094. PubDefElem: TOmfPublicNameElement;
  1095. OldCount,NewCount,i: Integer;
  1096. basegroup: TObjSectionGroup;
  1097. objsym: TObjSymbol;
  1098. objsec: TOmfObjSection;
  1099. begin
  1100. Result:=False;
  1101. PubDefRec:=TOmfRecord_PUBDEF.Create;
  1102. PubDefRec.PublicNames:=PubDefs;
  1103. OldCount:=PubDefs.Count;
  1104. PubDefRec.DecodeFrom(RawRec);
  1105. NewCount:=PubDefs.Count;
  1106. if (PubDefRec.BaseGroupIndex<0) or (PubDefRec.BaseGroupIndex>objdata.GroupsList.Count) then
  1107. begin
  1108. InputError('Public symbol''s group name index out of range');
  1109. PubDefRec.Free;
  1110. exit;
  1111. end;
  1112. if PubDefRec.BaseGroupIndex<>0 then
  1113. basegroup:=TObjSectionGroup(objdata.GroupsList[PubDefRec.BaseGroupIndex-1])
  1114. else
  1115. basegroup:=nil;
  1116. if (PubDefRec.BaseSegmentIndex<0) or (PubDefRec.BaseSegmentIndex>objdata.ObjSectionList.Count) then
  1117. begin
  1118. InputError('Public symbol''s segment name index out of range');
  1119. PubDefRec.Free;
  1120. exit;
  1121. end;
  1122. if PubDefRec.BaseSegmentIndex=0 then
  1123. begin
  1124. InputError('Public symbol uses absolute addressing, which is not supported by this linker');
  1125. PubDefRec.Free;
  1126. exit;
  1127. end;
  1128. objsec:=TOmfObjSection(objdata.ObjSectionList[PubDefRec.BaseSegmentIndex-1]);
  1129. for i:=OldCount to NewCount-1 do
  1130. begin
  1131. PubDefElem:=TOmfPublicNameElement(PubDefs[i]);
  1132. objsym:=objdata.CreateSymbol(PubDefElem.Name);
  1133. objsym.bind:=AB_GLOBAL;
  1134. objsym.typ:=AT_FUNCTION;
  1135. objsym.group:=basegroup;
  1136. objsym.objsection:=objsec;
  1137. objsym.offset:=PubDefElem.PublicOffset;
  1138. objsym.size:=0;
  1139. end;
  1140. PubDefRec.Free;
  1141. Result:=True;
  1142. end;
  1143. function TOmfObjInput.ReadModEnd(RawRec: TOmfRawRecord; objdata:TObjData): Boolean;
  1144. var
  1145. ModEndRec: TOmfRecord_MODEND;
  1146. objsym: TObjSymbol;
  1147. objsec: TOmfObjSection;
  1148. basegroup: TObjSectionGroup;
  1149. begin
  1150. Result:=False;
  1151. ModEndRec:=TOmfRecord_MODEND.Create;
  1152. ModEndRec.DecodeFrom(RawRec);
  1153. if ModEndRec.HasStartAddress then
  1154. begin
  1155. if not ModEndRec.LogicalStartAddress then
  1156. begin
  1157. InputError('Physical start address not supported');
  1158. ModEndRec.Free;
  1159. exit;
  1160. end;
  1161. if not (ModEndRec.TargetMethod in [ftmSegmentIndex,ftmSegmentIndexNoDisp]) then
  1162. begin
  1163. InputError('Target method for start address other than "Segment Index" is not supported');
  1164. ModEndRec.Free;
  1165. exit;
  1166. end;
  1167. if (ModEndRec.TargetDatum<1) or (ModEndRec.TargetDatum>objdata.ObjSectionList.Count) then
  1168. begin
  1169. InputError('Segment name index for start address out of range');
  1170. ModEndRec.Free;
  1171. exit;
  1172. end;
  1173. case ModEndRec.FrameMethod of
  1174. ffmSegmentIndex:
  1175. begin
  1176. if (ModEndRec.FrameDatum<1) or (ModEndRec.FrameDatum>objdata.ObjSectionList.Count) then
  1177. begin
  1178. InputError('Frame segment name index for start address out of range');
  1179. ModEndRec.Free;
  1180. exit;
  1181. end;
  1182. if ModEndRec.FrameDatum<>ModEndRec.TargetDatum then
  1183. begin
  1184. InputError('Frame segment different than target segment is not supported supported for start address');
  1185. ModEndRec.Free;
  1186. exit;
  1187. end;
  1188. basegroup:=nil;
  1189. end;
  1190. ffmGroupIndex:
  1191. begin
  1192. if (ModEndRec.FrameDatum<1) or (ModEndRec.FrameDatum>objdata.GroupsList.Count) then
  1193. begin
  1194. InputError('Frame group name index for start address out of range');
  1195. ModEndRec.Free;
  1196. exit;
  1197. end;
  1198. basegroup:=TObjSectionGroup(objdata.GroupsList[ModEndRec.FrameDatum-1]);
  1199. end;
  1200. else
  1201. begin
  1202. InputError('Frame method for start address other than "Segment Index" or "Group Index" is not supported');
  1203. ModEndRec.Free;
  1204. exit;
  1205. end;
  1206. end;
  1207. objsec:=TOmfObjSection(objdata.ObjSectionList[ModEndRec.TargetDatum-1]);
  1208. objsym:=objdata.CreateSymbol('..start');
  1209. objsym.bind:=AB_GLOBAL;
  1210. objsym.typ:=AT_FUNCTION;
  1211. objsym.group:=basegroup;
  1212. objsym.objsection:=objsec;
  1213. objsym.offset:=ModEndRec.TargetDisplacement;
  1214. objsym.size:=0;
  1215. end;
  1216. ModEndRec.Free;
  1217. Result:=True;
  1218. end;
  1219. function TOmfObjInput.ReadLEDataAndFixups(RawRec: TOmfRawRecord; objdata: TObjData): Boolean;
  1220. var
  1221. Is32Bit: Boolean;
  1222. NextOfs: Integer;
  1223. SegmentIndex: Integer;
  1224. EnumeratedDataOffset: DWord;
  1225. BlockLength: Integer;
  1226. objsec: TOmfObjSection;
  1227. FixupRawRec: TOmfRawRecord;
  1228. Fixup: TOmfSubRecord_FIXUP;
  1229. begin
  1230. Result:=False;
  1231. if not (RawRec.RecordType in [RT_LEDATA,RT_LEDATA32]) then
  1232. internalerror(2015040301);
  1233. Is32Bit:=RawRec.RecordType=RT_LEDATA32;
  1234. NextOfs:=RawRec.ReadIndexedRef(0,SegmentIndex);
  1235. if Is32Bit then
  1236. begin
  1237. if (NextOfs+3)>=RawRec.RecordLength then
  1238. internalerror(2015040504);
  1239. EnumeratedDataOffset := RawRec.RawData[NextOfs]+
  1240. (RawRec.RawData[NextOfs+1] shl 8)+
  1241. (RawRec.RawData[NextOfs+2] shl 16)+
  1242. (RawRec.RawData[NextOfs+3] shl 24);
  1243. Inc(NextOfs,4);
  1244. end
  1245. else
  1246. begin
  1247. if (NextOfs+1)>=RawRec.RecordLength then
  1248. internalerror(2015040504);
  1249. EnumeratedDataOffset := RawRec.RawData[NextOfs]+
  1250. (RawRec.RawData[NextOfs+1] shl 8);
  1251. Inc(NextOfs,2);
  1252. end;
  1253. BlockLength:=RawRec.RecordLength-NextOfs-1;
  1254. if BlockLength<0 then
  1255. internalerror(2015060501);
  1256. if BlockLength>1024 then
  1257. begin
  1258. InputError('LEDATA contains more than 1024 bytes of data');
  1259. exit;
  1260. end;
  1261. if (SegmentIndex<1) or (SegmentIndex>objdata.ObjSectionList.Count) then
  1262. begin
  1263. InputError('Segment index in LEDATA field is out of range');
  1264. exit;
  1265. end;
  1266. objsec:=TOmfObjSection(objdata.ObjSectionList[SegmentIndex-1]);
  1267. objsec.SecOptions:=objsec.SecOptions+[oso_Data];
  1268. if (objsec.Data.Size>EnumeratedDataOffset) then
  1269. begin
  1270. InputError('LEDATA enumerated data offset field out of sequence');
  1271. exit;
  1272. end;
  1273. if (EnumeratedDataOffset+BlockLength)>objsec.Size then
  1274. begin
  1275. InputError('LEDATA goes beyond the segment size declared in the SEGDEF record');
  1276. exit;
  1277. end;
  1278. objsec.Data.seek(EnumeratedDataOffset);
  1279. objsec.Data.write(RawRec.RawData[NextOfs],BlockLength);
  1280. { also read all the FIXUPP records that may follow }
  1281. while PeekNextRecordType in [RT_FIXUPP,RT_FIXUPP32] do
  1282. begin
  1283. FixupRawRec:=TOmfRawRecord.Create;
  1284. FixupRawRec.ReadFrom(FReader);
  1285. if not FRawRecord.VerifyChecksumByte then
  1286. begin
  1287. InputError('Invalid checksum in OMF record');
  1288. FixupRawRec.Free;
  1289. exit;
  1290. end;
  1291. NextOfs:=0;
  1292. Fixup:=TOmfSubRecord_FIXUP.Create;
  1293. Fixup.Is32Bit:=FixupRawRec.RecordType=RT_FIXUPP32;
  1294. Fixup.DataRecordStartOffset:=EnumeratedDataOffset;
  1295. while NextOfs<(FixupRawRec.RecordLength-1) do
  1296. begin
  1297. NextOfs:=Fixup.ReadAt(FixupRawRec,NextOfs);
  1298. if Fixup.FrameDeterminedByThread or Fixup.TargetDeterminedByThread then
  1299. begin
  1300. InputError('Fixups determined by thread not supported');
  1301. Fixup.Free;
  1302. FixupRawRec.Free;
  1303. exit;
  1304. end;
  1305. ImportOmfFixup(objdata,objsec,Fixup);
  1306. end;
  1307. Fixup.Free;
  1308. FixupRawRec.Free;
  1309. end;
  1310. Result:=True;
  1311. end;
  1312. function TOmfObjInput.ImportOmfFixup(objdata: TObjData; objsec: TOmfObjSection; Fixup: TOmfSubRecord_FIXUP): Boolean;
  1313. var
  1314. reloc: TOmfRelocation;
  1315. sym: TObjSymbol;
  1316. RelocType: TObjRelocationType;
  1317. target_section: TOmfObjSection;
  1318. target_group: TObjSectionGroup;
  1319. begin
  1320. Result:=False;
  1321. { range check location }
  1322. if (Fixup.LocationOffset+Fixup.LocationSize)>objsec.Size then
  1323. begin
  1324. InputError('Fixup location exceeds the current segment boundary');
  1325. exit;
  1326. end;
  1327. { range check target datum }
  1328. case Fixup.TargetMethod of
  1329. ftmSegmentIndex:
  1330. if (Fixup.TargetDatum<1) or (Fixup.TargetDatum>objdata.ObjSectionList.Count) then
  1331. begin
  1332. InputError('Segment name index in SI(<segment name>),<displacement> fixup target is out of range');
  1333. exit;
  1334. end;
  1335. ftmSegmentIndexNoDisp:
  1336. if (Fixup.TargetDatum<1) or (Fixup.TargetDatum>objdata.ObjSectionList.Count) then
  1337. begin
  1338. InputError('Segment name index in SI(<segment name>) fixup target is out of range');
  1339. exit;
  1340. end;
  1341. ftmGroupIndex:
  1342. if (Fixup.TargetDatum<1) or (Fixup.TargetDatum>objdata.GroupsList.Count) then
  1343. begin
  1344. InputError('Group name index in GI(<group name>),<displacement> fixup target is out of range');
  1345. exit;
  1346. end;
  1347. ftmGroupIndexNoDisp:
  1348. if (Fixup.TargetDatum<1) or (Fixup.TargetDatum>objdata.GroupsList.Count) then
  1349. begin
  1350. InputError('Group name index in GI(<group name>) fixup target is out of range');
  1351. exit;
  1352. end;
  1353. ftmExternalIndex:
  1354. if (Fixup.TargetDatum<1) or (Fixup.TargetDatum>ExtDefs.Count) then
  1355. begin
  1356. InputError('External symbol name index in EI(<symbol name>),<displacement> fixup target is out of range');
  1357. exit;
  1358. end;
  1359. ftmExternalIndexNoDisp:
  1360. if (Fixup.TargetDatum<1) or (Fixup.TargetDatum>ExtDefs.Count) then
  1361. begin
  1362. InputError('External symbol name index in EI(<symbol name>) fixup target is out of range');
  1363. exit;
  1364. end;
  1365. end;
  1366. { range check frame datum }
  1367. case Fixup.FrameMethod of
  1368. ffmSegmentIndex:
  1369. if (Fixup.FrameDatum<1) or (Fixup.FrameDatum>objdata.ObjSectionList.Count) then
  1370. begin
  1371. InputError('Segment name index in SI(<segment name>) fixup frame is out of range');
  1372. exit;
  1373. end;
  1374. ffmGroupIndex:
  1375. if (Fixup.FrameDatum<1) or (Fixup.FrameDatum>objdata.GroupsList.Count) then
  1376. begin
  1377. InputError('Group name index in GI(<group name>) fixup frame is out of range');
  1378. exit;
  1379. end;
  1380. ffmExternalIndex:
  1381. if (Fixup.TargetDatum<1) or (Fixup.TargetDatum>ExtDefs.Count) then
  1382. begin
  1383. InputError('External symbol name index in EI(<symbol name>) fixup frame is out of range');
  1384. exit;
  1385. end;
  1386. end;
  1387. if Fixup.TargetMethod in [ftmExternalIndex,ftmExternalIndexNoDisp] then
  1388. begin
  1389. sym:=objdata.symbolref(TOmfExternalNameElement(ExtDefs[Fixup.TargetDatum-1]).Name);
  1390. case Fixup.LocationType of
  1391. fltOffset:
  1392. case Fixup.Mode of
  1393. fmSegmentRelative:
  1394. RelocType:=RELOC_ABSOLUTE;
  1395. fmSelfRelative:
  1396. RelocType:=RELOC_RELATIVE;
  1397. end;
  1398. fltBase:
  1399. case Fixup.Mode of
  1400. fmSegmentRelative:
  1401. RelocType:=RELOC_SEG;
  1402. fmSelfRelative:
  1403. RelocType:=RELOC_SEGREL;
  1404. end;
  1405. else
  1406. begin
  1407. InputError('Unsupported fixup location type '+IntToStr(Ord(Fixup.LocationType))+' in external reference to '+sym.Name);
  1408. exit;
  1409. end;
  1410. end;
  1411. reloc:=TOmfRelocation.CreateSymbol(Fixup.LocationOffset,sym,RelocType);
  1412. objsec.ObjRelocations.Add(reloc);
  1413. case Fixup.FrameMethod of
  1414. ffmTarget:
  1415. {nothing};
  1416. ffmGroupIndex:
  1417. reloc.FrameGroup:=TObjSectionGroup(objdata.GroupsList[Fixup.FrameDatum-1]).Name;
  1418. else
  1419. begin
  1420. InputError('Unsupported frame method '+IntToStr(Ord(Fixup.FrameMethod))+' in external reference to '+sym.Name);
  1421. exit;
  1422. end;
  1423. end;
  1424. if Fixup.TargetDisplacement<>0 then
  1425. begin
  1426. InputError('Unsupported nonzero target displacement '+IntToStr(Fixup.TargetDisplacement)+' in external reference to '+sym.Name);
  1427. exit;
  1428. end;
  1429. end
  1430. else if Fixup.TargetMethod in [ftmSegmentIndex,ftmSegmentIndexNoDisp] then
  1431. begin
  1432. target_section:=TOmfObjSection(objdata.ObjSectionList[Fixup.TargetDatum-1]);
  1433. case Fixup.LocationType of
  1434. fltOffset:
  1435. case Fixup.Mode of
  1436. fmSegmentRelative:
  1437. RelocType:=RELOC_ABSOLUTE;
  1438. fmSelfRelative:
  1439. RelocType:=RELOC_RELATIVE;
  1440. end;
  1441. fltBase:
  1442. case Fixup.Mode of
  1443. fmSegmentRelative:
  1444. RelocType:=RELOC_SEG;
  1445. fmSelfRelative:
  1446. RelocType:=RELOC_SEGREL;
  1447. end;
  1448. else
  1449. begin
  1450. InputError('Unsupported fixup location type '+IntToStr(Ord(Fixup.LocationType))+' in reference to segment '+target_section.Name);
  1451. exit;
  1452. end;
  1453. end;
  1454. reloc:=TOmfRelocation.CreateSection(Fixup.LocationOffset,target_section,RelocType);
  1455. objsec.ObjRelocations.Add(reloc);
  1456. case Fixup.FrameMethod of
  1457. ffmTarget:
  1458. {nothing};
  1459. ffmGroupIndex:
  1460. reloc.FrameGroup:=TObjSectionGroup(objdata.GroupsList[Fixup.FrameDatum-1]).Name;
  1461. else
  1462. begin
  1463. InputError('Unsupported frame method '+IntToStr(Ord(Fixup.FrameMethod))+' in reference to segment '+target_section.Name);
  1464. exit;
  1465. end;
  1466. end;
  1467. if Fixup.TargetDisplacement<>0 then
  1468. begin
  1469. InputError('Unsupported nonzero target displacement '+IntToStr(Fixup.TargetDisplacement)+' in reference to segment '+target_section.Name);
  1470. exit;
  1471. end;
  1472. end
  1473. else if Fixup.TargetMethod in [ftmGroupIndex,ftmGroupIndexNoDisp] then
  1474. begin
  1475. target_group:=TObjSectionGroup(objdata.GroupsList[Fixup.TargetDatum-1]);
  1476. if target_group.Name<>'DGROUP' then
  1477. begin
  1478. InputError('Fixup target group other than "DGROUP" is not supported');
  1479. exit;
  1480. end;
  1481. case Fixup.LocationType of
  1482. fltBase:
  1483. case Fixup.Mode of
  1484. fmSegmentRelative:
  1485. RelocType:=RELOC_DGROUP;
  1486. fmSelfRelative:
  1487. RelocType:=RELOC_DGROUPREL;
  1488. end;
  1489. else
  1490. begin
  1491. InputError('Unsupported fixup location type '+IntToStr(Ord(Fixup.LocationType))+' in reference to group '+target_group.Name);
  1492. exit;
  1493. end;
  1494. end;
  1495. reloc:=TOmfRelocation.CreateSection(Fixup.LocationOffset,nil,RelocType);
  1496. objsec.ObjRelocations.Add(reloc);
  1497. case Fixup.FrameMethod of
  1498. ffmTarget:
  1499. {nothing};
  1500. else
  1501. begin
  1502. InputError('Unsupported frame method '+IntToStr(Ord(Fixup.FrameMethod))+' in reference to group '+target_group.Name);
  1503. exit;
  1504. end;
  1505. end;
  1506. if Fixup.TargetDisplacement<>0 then
  1507. begin
  1508. InputError('Unsupported nonzero target displacement '+IntToStr(Fixup.TargetDisplacement)+' in reference to group '+target_group.Name);
  1509. exit;
  1510. end;
  1511. end
  1512. else
  1513. begin
  1514. {todo: convert other fixup types as well }
  1515. InputError('Unsupported fixup target method '+IntToStr(Ord(Fixup.TargetMethod)));
  1516. exit;
  1517. end;
  1518. Result:=True;
  1519. end;
  1520. constructor TOmfObjInput.create;
  1521. begin
  1522. inherited create;
  1523. cobjdata:=TOmfObjData;
  1524. FLNames:=TOmfOrderedNameCollection.Create;
  1525. FExtDefs:=TFPHashObjectList.Create;
  1526. FPubDefs:=TFPHashObjectList.Create;
  1527. FRawRecord:=TOmfRawRecord.Create;
  1528. CaseSensitive:=False;
  1529. end;
  1530. destructor TOmfObjInput.destroy;
  1531. begin
  1532. FRawRecord.Free;
  1533. FPubDefs.Free;
  1534. FExtDefs.Free;
  1535. FLNames.Free;
  1536. inherited destroy;
  1537. end;
  1538. class function TOmfObjInput.CanReadObjData(AReader: TObjectreader): boolean;
  1539. var
  1540. b: Byte;
  1541. begin
  1542. result:=false;
  1543. if AReader.Read(b,sizeof(b)) then
  1544. begin
  1545. if b=RT_THEADR then
  1546. { TODO: check additional fields }
  1547. result:=true;
  1548. end;
  1549. AReader.Seek(0);
  1550. end;
  1551. function TOmfObjInput.ReadObjData(AReader: TObjectreader; out objdata: TObjData): boolean;
  1552. begin
  1553. FReader:=AReader;
  1554. InputFileName:=AReader.FileName;
  1555. objdata:=CObjData.Create(InputFileName);
  1556. result:=false;
  1557. LNames.Clear;
  1558. ExtDefs.Clear;
  1559. FRawRecord.ReadFrom(FReader);
  1560. if not FRawRecord.VerifyChecksumByte then
  1561. begin
  1562. InputError('Invalid checksum in OMF record');
  1563. exit;
  1564. end;
  1565. if FRawRecord.RecordType<>RT_THEADR then
  1566. begin
  1567. InputError('Can''t read OMF header');
  1568. exit;
  1569. end;
  1570. repeat
  1571. FRawRecord.ReadFrom(FReader);
  1572. if not FRawRecord.VerifyChecksumByte then
  1573. begin
  1574. InputError('Invalid checksum in OMF record');
  1575. exit;
  1576. end;
  1577. case FRawRecord.RecordType of
  1578. RT_LNAMES:
  1579. if not ReadLNames(FRawRecord) then
  1580. exit;
  1581. RT_SEGDEF,RT_SEGDEF32:
  1582. if not ReadSegDef(FRawRecord,objdata) then
  1583. exit;
  1584. RT_GRPDEF:
  1585. if not ReadGrpDef(FRawRecord,objdata) then
  1586. exit;
  1587. RT_COMENT:
  1588. begin
  1589. {todo}
  1590. end;
  1591. RT_EXTDEF:
  1592. if not ReadExtDef(FRawRecord,objdata) then
  1593. exit;
  1594. RT_PUBDEF,RT_PUBDEF32:
  1595. if not ReadPubDef(FRawRecord,objdata) then
  1596. exit;
  1597. RT_LEDATA,RT_LEDATA32:
  1598. if not ReadLEDataAndFixups(FRawRecord,objdata) then
  1599. exit;
  1600. RT_LIDATA,RT_LIDATA32:
  1601. begin
  1602. InputError('LIDATA records are not supported');
  1603. exit;
  1604. end;
  1605. RT_FIXUPP,RT_FIXUPP32:
  1606. begin
  1607. InputError('FIXUPP record is invalid, because it does not follow a LEDATA or LIDATA record');
  1608. exit;
  1609. end;
  1610. RT_MODEND,RT_MODEND32:
  1611. if not ReadModEnd(FRawRecord,objdata) then
  1612. exit;
  1613. else
  1614. begin
  1615. InputError('Unsupported OMF record type $'+HexStr(FRawRecord.RecordType,2));
  1616. exit;
  1617. end;
  1618. end;
  1619. until FRawRecord.RecordType in [RT_MODEND,RT_MODEND32];
  1620. result:=true;
  1621. end;
  1622. {****************************************************************************
  1623. TMZExeHeader
  1624. ****************************************************************************}
  1625. procedure TMZExeHeader.SetHeaderSizeAlignment(AValue: Integer);
  1626. begin
  1627. if (AValue<16) or ((AValue mod 16) <> 0) then
  1628. Internalerror(2015060601);
  1629. FHeaderSizeAlignment:=AValue;
  1630. end;
  1631. constructor TMZExeHeader.Create;
  1632. begin
  1633. FHeaderSizeAlignment:=16;
  1634. end;
  1635. procedure TMZExeHeader.WriteTo(aWriter: TObjectWriter);
  1636. var
  1637. NumRelocs: Word;
  1638. HeaderSizeInBytes: DWord;
  1639. HeaderParagraphs: Word;
  1640. RelocTableOffset: Word;
  1641. BytesInLastBlock: Word;
  1642. BlocksInFile: Word;
  1643. HeaderBytes: array [0..$1B] of Byte;
  1644. RelocBytes: array [0..3] of Byte;
  1645. TotalExeSize: DWord;
  1646. i: Integer;
  1647. begin
  1648. NumRelocs:=Length(Relocations);
  1649. RelocTableOffset:=$1C+Length(ExtraHeaderData);
  1650. HeaderSizeInBytes:=Align(RelocTableOffset+4*NumRelocs,16);
  1651. HeaderParagraphs:=HeaderSizeInBytes div 16;
  1652. TotalExeSize:=HeaderSizeInBytes+LoadableImageSize;
  1653. BlocksInFile:=(TotalExeSize+511) div 512;
  1654. BytesInLastBlock:=TotalExeSize mod 512;
  1655. HeaderBytes[$00]:=$4D; { 'M' }
  1656. HeaderBytes[$01]:=$5A; { 'Z' }
  1657. HeaderBytes[$02]:=Byte(BytesInLastBlock);
  1658. HeaderBytes[$03]:=Byte(BytesInLastBlock shr 8);
  1659. HeaderBytes[$04]:=Byte(BlocksInFile);
  1660. HeaderBytes[$05]:=Byte(BlocksInFile shr 8);
  1661. HeaderBytes[$06]:=Byte(NumRelocs);
  1662. HeaderBytes[$07]:=Byte(NumRelocs shr 8);
  1663. HeaderBytes[$08]:=Byte(HeaderParagraphs);
  1664. HeaderBytes[$09]:=Byte(HeaderParagraphs shr 8);
  1665. HeaderBytes[$0A]:=Byte(MinExtraParagraphs);
  1666. HeaderBytes[$0B]:=Byte(MinExtraParagraphs shr 8);
  1667. HeaderBytes[$0C]:=Byte(MaxExtraParagraphs);
  1668. HeaderBytes[$0D]:=Byte(MaxExtraParagraphs shr 8);
  1669. HeaderBytes[$0E]:=Byte(InitialSS);
  1670. HeaderBytes[$0F]:=Byte(InitialSS shr 8);
  1671. HeaderBytes[$10]:=Byte(InitialSP);
  1672. HeaderBytes[$11]:=Byte(InitialSP shr 8);
  1673. HeaderBytes[$12]:=Byte(Checksum);
  1674. HeaderBytes[$13]:=Byte(Checksum shr 8);
  1675. HeaderBytes[$14]:=Byte(InitialIP);
  1676. HeaderBytes[$15]:=Byte(InitialIP shr 8);
  1677. HeaderBytes[$16]:=Byte(InitialCS);
  1678. HeaderBytes[$17]:=Byte(InitialCS shr 8);
  1679. HeaderBytes[$18]:=Byte(RelocTableOffset);
  1680. HeaderBytes[$19]:=Byte(RelocTableOffset shr 8);
  1681. HeaderBytes[$1A]:=Byte(OverlayNumber);
  1682. HeaderBytes[$1B]:=Byte(OverlayNumber shr 8);
  1683. aWriter.write(HeaderBytes[0],$1C);
  1684. aWriter.write(ExtraHeaderData[0],Length(ExtraHeaderData));
  1685. for i:=0 to NumRelocs-1 do
  1686. with Relocations[i] do
  1687. begin
  1688. RelocBytes[0]:=Byte(offset);
  1689. RelocBytes[1]:=Byte(offset shr 8);
  1690. RelocBytes[2]:=Byte(segment);
  1691. RelocBytes[3]:=Byte(segment shr 8);
  1692. aWriter.write(RelocBytes[0],4);
  1693. end;
  1694. { pad with zeros until the end of header (paragraph aligned) }
  1695. aWriter.WriteZeros(HeaderSizeInBytes-aWriter.Size);
  1696. end;
  1697. procedure TMZExeHeader.AddRelocation(aSegment, aOffset: Word);
  1698. begin
  1699. SetLength(FRelocations,Length(FRelocations)+1);
  1700. with FRelocations[High(FRelocations)] do
  1701. begin
  1702. segment:=aSegment;
  1703. offset:=aOffset;
  1704. end;
  1705. end;
  1706. {****************************************************************************
  1707. TMZExeSection
  1708. ****************************************************************************}
  1709. procedure TMZExeSection.AddObjSection(objsec: TObjSection; ignoreprops: boolean);
  1710. begin
  1711. { allow mixing initialized and uninitialized data in the same section
  1712. => set ignoreprops=true }
  1713. inherited AddObjSection(objsec,true);
  1714. end;
  1715. {****************************************************************************
  1716. TMZExeUnifiedLogicalSegment
  1717. ****************************************************************************}
  1718. constructor TMZExeUnifiedLogicalSegment.create(HashObjectList: TFPHashObjectList; const s: TSymStr);
  1719. var
  1720. Separator: SizeInt;
  1721. begin
  1722. inherited create(HashObjectList,s);
  1723. FObjSectionList:=TFPObjectList.Create(false);
  1724. { name format is 'SegName||ClassName' }
  1725. Separator:=Pos('||',s);
  1726. if Separator>0 then
  1727. begin
  1728. FSegName:=Copy(s,1,Separator-1);
  1729. FSegClass:=Copy(s,Separator+2,Length(s)-Separator-1);
  1730. end
  1731. else
  1732. begin
  1733. FSegName:=Name;
  1734. FSegClass:='';
  1735. end;
  1736. { wlink recognizes the stack segment by the class name 'STACK' }
  1737. { let's be compatible with wlink }
  1738. IsStack:=FSegClass='STACK';
  1739. end;
  1740. destructor TMZExeUnifiedLogicalSegment.destroy;
  1741. begin
  1742. FObjSectionList.Free;
  1743. inherited destroy;
  1744. end;
  1745. procedure TMZExeUnifiedLogicalSegment.AddObjSection(ObjSec: TOmfObjSection);
  1746. begin
  1747. ObjSectionList.Add(ObjSec);
  1748. ObjSec.MZExeUnifiedLogicalSegment:=self;
  1749. { tlink (and ms link?) use the scStack segment combination to recognize
  1750. the stack segment.
  1751. let's be compatible with tlink as well }
  1752. if ObjSec.Combination=scStack then
  1753. IsStack:=True;
  1754. end;
  1755. procedure TMZExeUnifiedLogicalSegment.CalcMemPos;
  1756. var
  1757. MinMemPos: qword=high(qword);
  1758. MaxMemPos: qword=0;
  1759. objsec: TOmfObjSection;
  1760. i: Integer;
  1761. begin
  1762. if ObjSectionList.Count=0 then
  1763. internalerror(2015082201);
  1764. for i:=0 to ObjSectionList.Count-1 do
  1765. begin
  1766. objsec:=TOmfObjSection(ObjSectionList[i]);
  1767. if objsec.MemPos<MinMemPos then
  1768. MinMemPos:=objsec.MemPos;
  1769. if (objsec.MemPos+objsec.Size)>MaxMemPos then
  1770. MaxMemPos:=objsec.MemPos+objsec.Size;
  1771. end;
  1772. MemPos:=MinMemPos;
  1773. Size:=MaxMemPos-MemPos;
  1774. end;
  1775. function TMZExeUnifiedLogicalSegment.MemPosStr: string;
  1776. begin
  1777. Result:=HexStr(MemBasePos shr 4,4)+':'+HexStr((MemPos-MemBasePos),4);
  1778. end;
  1779. {****************************************************************************
  1780. TMZExeUnifiedLogicalGroup
  1781. ****************************************************************************}
  1782. constructor TMZExeUnifiedLogicalGroup.create(HashObjectList: TFPHashObjectList; const s: TSymStr);
  1783. begin
  1784. inherited create(HashObjectList,s);
  1785. FSegmentList:=TFPHashObjectList.Create(false);
  1786. end;
  1787. destructor TMZExeUnifiedLogicalGroup.destroy;
  1788. begin
  1789. FSegmentList.Free;
  1790. inherited destroy;
  1791. end;
  1792. procedure TMZExeUnifiedLogicalGroup.CalcMemPos;
  1793. var
  1794. MinMemPos: qword=high(qword);
  1795. MaxMemPos: qword=0;
  1796. UniSeg: TMZExeUnifiedLogicalSegment;
  1797. i: Integer;
  1798. begin
  1799. if SegmentList.Count=0 then
  1800. internalerror(2015082201);
  1801. for i:=0 to SegmentList.Count-1 do
  1802. begin
  1803. UniSeg:=TMZExeUnifiedLogicalSegment(SegmentList[i]);
  1804. if UniSeg.MemPos<MinMemPos then
  1805. MinMemPos:=UniSeg.MemPos;
  1806. if (UniSeg.MemPos+UniSeg.Size)>MaxMemPos then
  1807. MaxMemPos:=UniSeg.MemPos+UniSeg.Size;
  1808. end;
  1809. { align *down* on a paragraph boundary }
  1810. MemPos:=(MinMemPos shr 4) shl 4;
  1811. Size:=MaxMemPos-MemPos;
  1812. end;
  1813. function TMZExeUnifiedLogicalGroup.MemPosStr: string;
  1814. begin
  1815. Result:=HexStr(MemPos shr 4,4)+':'+HexStr(MemPos and $f,4);
  1816. end;
  1817. procedure TMZExeUnifiedLogicalGroup.AddSegment(UniSeg: TMZExeUnifiedLogicalSegment);
  1818. begin
  1819. SegmentList.Add(UniSeg.Name,UniSeg);
  1820. if UniSeg.PrimaryGroup='' then
  1821. UniSeg.PrimaryGroup:=Name;
  1822. end;
  1823. {****************************************************************************
  1824. TMZExeOutput
  1825. ****************************************************************************}
  1826. function TMZExeOutput.GetMZFlatContentSection: TMZExeSection;
  1827. begin
  1828. if not assigned(FMZFlatContentSection) then
  1829. FMZFlatContentSection:=TMZExeSection(FindExeSection('.MZ_flat_content'));
  1830. result:=FMZFlatContentSection;
  1831. end;
  1832. procedure TMZExeOutput.CalcExeUnifiedLogicalSegments;
  1833. var
  1834. ExeSec: TMZExeSection;
  1835. ObjSec: TOmfObjSection;
  1836. UniSeg: TMZExeUnifiedLogicalSegment;
  1837. i: Integer;
  1838. begin
  1839. ExeSec:=MZFlatContentSection;
  1840. for i:=0 to ExeSec.ObjSectionList.Count-1 do
  1841. begin
  1842. ObjSec:=TOmfObjSection(ExeSec.ObjSectionList[i]);
  1843. UniSeg:=TMZExeUnifiedLogicalSegment(ExeUnifiedLogicalSegments.Find(ObjSec.Name));
  1844. if not assigned(UniSeg) then
  1845. UniSeg:=TMZExeUnifiedLogicalSegment.Create(ExeUnifiedLogicalSegments,ObjSec.Name);
  1846. UniSeg.AddObjSection(ObjSec);
  1847. end;
  1848. for i:=0 to ExeUnifiedLogicalSegments.Count-1 do
  1849. begin
  1850. UniSeg:=TMZExeUnifiedLogicalSegment(ExeUnifiedLogicalSegments[i]);
  1851. UniSeg.CalcMemPos;
  1852. if UniSeg.Size>$10000 then
  1853. begin
  1854. if current_settings.x86memorymodel=mm_tiny then
  1855. Message1(link_e_program_segment_too_large,IntToStr(UniSeg.Size-$10000))
  1856. else if UniSeg.SegClass='CODE' then
  1857. Message1(link_e_code_segment_too_large,IntToStr(UniSeg.Size-$10000))
  1858. else if UniSeg.SegClass='DATA' then
  1859. Message1(link_e_data_segment_too_large,IntToStr(UniSeg.Size-$10000))
  1860. else
  1861. Message2(link_e_segment_too_large,UniSeg.SegName,IntToStr(UniSeg.Size-$10000));
  1862. end;
  1863. end;
  1864. end;
  1865. procedure TMZExeOutput.CalcExeGroups;
  1866. procedure AddToGroup(UniSeg:TMZExeUnifiedLogicalSegment;GroupName:TSymStr);
  1867. var
  1868. Group: TMZExeUnifiedLogicalGroup;
  1869. begin
  1870. Group:=TMZExeUnifiedLogicalGroup(ExeUnifiedLogicalGroups.Find(GroupName));
  1871. if not assigned(Group) then
  1872. Group:=TMZExeUnifiedLogicalGroup.Create(ExeUnifiedLogicalGroups,GroupName);
  1873. Group.AddSegment(UniSeg);
  1874. end;
  1875. var
  1876. objdataidx,groupidx,secidx: Integer;
  1877. ObjData: TObjData;
  1878. ObjGroup: TObjSectionGroup;
  1879. ObjSec: TOmfObjSection;
  1880. UniGrp: TMZExeUnifiedLogicalGroup;
  1881. begin
  1882. for objdataidx:=0 to ObjDataList.Count-1 do
  1883. begin
  1884. ObjData:=TObjData(ObjDataList[objdataidx]);
  1885. if assigned(ObjData.GroupsList) then
  1886. for groupidx:=0 to ObjData.GroupsList.Count-1 do
  1887. begin
  1888. ObjGroup:=TObjSectionGroup(ObjData.GroupsList[groupidx]);
  1889. for secidx:=low(ObjGroup.members) to high(ObjGroup.members) do
  1890. begin
  1891. ObjSec:=TOmfObjSection(ObjGroup.members[secidx]);
  1892. if assigned(ObjSec.MZExeUnifiedLogicalSegment) then
  1893. AddToGroup(ObjSec.MZExeUnifiedLogicalSegment,ObjGroup.Name);
  1894. end;
  1895. end;
  1896. end;
  1897. for groupidx:=0 to ExeUnifiedLogicalGroups.Count-1 do
  1898. begin
  1899. UniGrp:=TMZExeUnifiedLogicalGroup(ExeUnifiedLogicalGroups[groupidx]);
  1900. UniGrp.CalcMemPos;
  1901. if UniGrp.Size>$10000 then
  1902. begin
  1903. if current_settings.x86memorymodel=mm_tiny then
  1904. Message1(link_e_program_segment_too_large,IntToStr(UniGrp.Size-$10000))
  1905. else if UniGrp.Name='DGROUP' then
  1906. Message1(link_e_data_segment_too_large,IntToStr(UniGrp.Size-$10000))
  1907. else
  1908. Message2(link_e_group_too_large,UniGrp.Name,IntToStr(UniGrp.Size-$10000));
  1909. end;
  1910. end;
  1911. end;
  1912. procedure TMZExeOutput.CalcSegments_MemBasePos;
  1913. var
  1914. lastbase:qword=0;
  1915. i: Integer;
  1916. UniSeg: TMZExeUnifiedLogicalSegment;
  1917. begin
  1918. for i:=0 to ExeUnifiedLogicalSegments.Count-1 do
  1919. begin
  1920. UniSeg:=TMZExeUnifiedLogicalSegment(ExeUnifiedLogicalSegments[i]);
  1921. if (UniSeg.PrimaryGroup<>'') or (UniSeg.IsStack) or
  1922. (((UniSeg.MemPos+UniSeg.Size-1)-lastbase)>$ffff) then
  1923. lastbase:=(UniSeg.MemPos shr 4) shl 4;
  1924. UniSeg.MemBasePos:=lastbase;
  1925. end;
  1926. end;
  1927. procedure TMZExeOutput.WriteMap_SegmentsAndGroups;
  1928. var
  1929. i: Integer;
  1930. UniSeg: TMZExeUnifiedLogicalSegment;
  1931. UniGrp: TMZExeUnifiedLogicalGroup;
  1932. begin
  1933. exemap.AddHeader('Groups list');
  1934. exemap.Add('');
  1935. exemap.Add(PadSpace('Group',32)+PadSpace('Address',21)+'Size');
  1936. exemap.Add(PadSpace('=====',32)+PadSpace('=======',21)+'====');
  1937. exemap.Add('');
  1938. for i:=0 to ExeUnifiedLogicalGroups.Count-1 do
  1939. begin
  1940. UniGrp:=TMZExeUnifiedLogicalGroup(ExeUnifiedLogicalGroups[i]);
  1941. exemap.Add(PadSpace(UniGrp.Name,32)+PadSpace(UniGrp.MemPosStr,21)+HexStr(UniGrp.Size,8));
  1942. end;
  1943. exemap.Add('');
  1944. exemap.AddHeader('Segments list');
  1945. exemap.Add('');
  1946. exemap.Add(PadSpace('Segment',23)+PadSpace('Class',15)+PadSpace('Group',15)+PadSpace('Address',16)+'Size');
  1947. exemap.Add(PadSpace('=======',23)+PadSpace('=====',15)+PadSpace('=====',15)+PadSpace('=======',16)+'====');
  1948. exemap.Add('');
  1949. for i:=0 to ExeUnifiedLogicalSegments.Count-1 do
  1950. begin
  1951. UniSeg:=TMZExeUnifiedLogicalSegment(ExeUnifiedLogicalSegments[i]);
  1952. exemap.Add(PadSpace(UniSeg.SegName,23)+PadSpace(UniSeg.SegClass,15)+PadSpace(UniSeg.PrimaryGroup,15)+PadSpace(UniSeg.MemPosStr,16)+HexStr(UniSeg.Size,8));
  1953. end;
  1954. exemap.Add('');
  1955. end;
  1956. procedure TMZExeOutput.WriteMap_HeaderData;
  1957. begin
  1958. exemap.AddHeader('Header data');
  1959. exemap.Add('Loadable image size: '+HexStr(Header.LoadableImageSize,8));
  1960. exemap.Add('Min extra paragraphs: '+HexStr(Header.MinExtraParagraphs,4));
  1961. exemap.Add('Max extra paragraphs: '+HexStr(Header.MaxExtraParagraphs,4));
  1962. exemap.Add('Initial stack pointer: '+HexStr(Header.InitialSS,4)+':'+HexStr(Header.InitialSP,4));
  1963. exemap.Add('Entry point address: '+HexStr(Header.InitialCS,4)+':'+HexStr(Header.InitialIP,4));
  1964. end;
  1965. function TMZExeOutput.FindStackSegment: TMZExeUnifiedLogicalSegment;
  1966. var
  1967. i: Integer;
  1968. stackseg_wannabe: TMZExeUnifiedLogicalSegment;
  1969. begin
  1970. Result:=nil;
  1971. for i:=0 to ExeUnifiedLogicalSegments.Count-1 do
  1972. begin
  1973. stackseg_wannabe:=TMZExeUnifiedLogicalSegment(ExeUnifiedLogicalSegments[i]);
  1974. { if there are multiple stack segments, choose the largest one.
  1975. In theory, we're probably supposed to combine them all and put
  1976. them in a contiguous location in memory, but we don't care }
  1977. if stackseg_wannabe.IsStack and
  1978. (not assigned(result) or (Result.Size<stackseg_wannabe.Size)) then
  1979. Result:=stackseg_wannabe;
  1980. end;
  1981. end;
  1982. procedure TMZExeOutput.FillLoadableImageSize;
  1983. var
  1984. i: Integer;
  1985. ExeSec: TMZExeSection;
  1986. ObjSec: TOmfObjSection;
  1987. StartDataPos: LongWord;
  1988. buf: array [0..1023] of byte;
  1989. bytesread: LongWord;
  1990. begin
  1991. Header.LoadableImageSize:=0;
  1992. ExeSec:=MZFlatContentSection;
  1993. for i:=0 to ExeSec.ObjSectionList.Count-1 do
  1994. begin
  1995. ObjSec:=TOmfObjSection(ExeSec.ObjSectionList[i]);
  1996. if (ObjSec.Size>0) and assigned(ObjSec.Data) then
  1997. if (ObjSec.MemPos+ObjSec.Size)>Header.LoadableImageSize then
  1998. Header.LoadableImageSize:=ObjSec.MemPos+ObjSec.Size;
  1999. end;
  2000. end;
  2001. procedure TMZExeOutput.FillMinExtraParagraphs;
  2002. var
  2003. ExeSec: TMZExeSection;
  2004. begin
  2005. ExeSec:=MZFlatContentSection;
  2006. Header.MinExtraParagraphs:=(align(ExeSec.Size,16)-align(Header.LoadableImageSize,16)) div 16;
  2007. end;
  2008. procedure TMZExeOutput.FillMaxExtraParagraphs;
  2009. var
  2010. heapmin_paragraphs: Integer;
  2011. heapmax_paragraphs: Integer;
  2012. begin
  2013. if current_settings.x86memorymodel in x86_far_data_models then
  2014. begin
  2015. { calculate the additional number of paragraphs needed }
  2016. heapmin_paragraphs:=(heapsize + 15) div 16;
  2017. heapmax_paragraphs:=(maxheapsize + 15) div 16;
  2018. Header.MaxExtraParagraphs:=min(Header.MinExtraParagraphs-heapmin_paragraphs+heapmax_paragraphs,$FFFF);
  2019. end
  2020. else
  2021. Header.MaxExtraParagraphs:=$FFFF;
  2022. end;
  2023. procedure TMZExeOutput.FillStartAddress;
  2024. var
  2025. EntryMemPos: qword;
  2026. EntryMemBasePos: qword;
  2027. begin
  2028. EntryMemPos:=EntrySym.address;
  2029. if assigned(EntrySym.group) then
  2030. EntryMemBasePos:=TMZExeUnifiedLogicalGroup(ExeUnifiedLogicalGroups.Find(EntrySym.group.Name)).MemPos
  2031. else
  2032. EntryMemBasePos:=TOmfObjSection(EntrySym.objsection).MZExeUnifiedLogicalSegment.MemBasePos;
  2033. Header.InitialIP:=EntryMemPos-EntryMemBasePos;
  2034. Header.InitialCS:=EntryMemBasePos shr 4;
  2035. end;
  2036. procedure TMZExeOutput.FillStackAddress;
  2037. var
  2038. stackseg: TMZExeUnifiedLogicalSegment;
  2039. begin
  2040. stackseg:=FindStackSegment;
  2041. if assigned(stackseg) then
  2042. begin
  2043. Header.InitialSS:=stackseg.MemBasePos shr 4;
  2044. Header.InitialSP:=stackseg.MemPos+stackseg.Size-stackseg.MemBasePos;
  2045. end
  2046. else
  2047. begin
  2048. Header.InitialSS:=0;
  2049. Header.InitialSP:=0;
  2050. end;
  2051. end;
  2052. procedure TMZExeOutput.FillHeaderData;
  2053. begin
  2054. Header.MaxExtraParagraphs:=$FFFF;
  2055. FillLoadableImageSize;
  2056. FillMinExtraParagraphs;
  2057. FillMaxExtraParagraphs;
  2058. FillStartAddress;
  2059. FillStackAddress;
  2060. if assigned(exemap) then
  2061. WriteMap_HeaderData;
  2062. end;
  2063. function TMZExeOutput.writeExe: boolean;
  2064. var
  2065. ExeSec: TMZExeSection;
  2066. i: Integer;
  2067. ObjSec: TOmfObjSection;
  2068. begin
  2069. Result:=False;
  2070. FillHeaderData;
  2071. Header.WriteTo(FWriter);
  2072. ExeSec:=MZFlatContentSection;
  2073. ExeSec.DataPos:=FWriter.Size;
  2074. for i:=0 to ExeSec.ObjSectionList.Count-1 do
  2075. begin
  2076. ObjSec:=TOmfObjSection(ExeSec.ObjSectionList[i]);
  2077. if ObjSec.MemPos<Header.LoadableImageSize then
  2078. begin
  2079. FWriter.WriteZeros(max(0,ObjSec.MemPos-FWriter.Size+ExeSec.DataPos));
  2080. if assigned(ObjSec.Data) then
  2081. FWriter.writearray(ObjSec.Data);
  2082. end;
  2083. end;
  2084. Result:=True;
  2085. end;
  2086. function TMZExeOutput.writeCom: boolean;
  2087. const
  2088. ComFileOffset=$100;
  2089. var
  2090. i: Integer;
  2091. ExeSec: TMZExeSection;
  2092. ObjSec: TOmfObjSection;
  2093. StartDataPos: LongWord;
  2094. buf: array [0..1023] of byte;
  2095. bytesread: LongWord;
  2096. begin
  2097. FillHeaderData;
  2098. ExeSec:=MZFlatContentSection;
  2099. for i:=0 to ExeSec.ObjSectionList.Count-1 do
  2100. begin
  2101. ObjSec:=TOmfObjSection(ExeSec.ObjSectionList[i]);
  2102. if ObjSec.MemPos<Header.LoadableImageSize then
  2103. begin
  2104. FWriter.WriteZeros(max(0,ObjSec.MemPos-ComFileOffset-FWriter.Size));
  2105. if assigned(ObjSec.Data) then
  2106. begin
  2107. if ObjSec.MemPos<ComFileOffset then
  2108. begin
  2109. ObjSec.Data.seek(ComFileOffset-ObjSec.MemPos);
  2110. repeat
  2111. bytesread:=ObjSec.Data.read(buf,sizeof(buf));
  2112. if bytesread<>0 then
  2113. FWriter.write(buf,bytesread);
  2114. until bytesread=0;
  2115. end
  2116. else
  2117. FWriter.writearray(ObjSec.Data);
  2118. end;
  2119. end;
  2120. end;
  2121. Result:=True;
  2122. end;
  2123. procedure TMZExeOutput.Load_Symbol(const aname: string);
  2124. var
  2125. dgroup: TObjSectionGroup;
  2126. sym: TObjSymbol;
  2127. begin
  2128. { special handling for the '_edata' and '_end' symbols, which are
  2129. internally added by the linker }
  2130. if (aname='_edata') or (aname='_end') then
  2131. begin
  2132. { create an internal segment with the 'BSS' class }
  2133. internalObjData.createsection('*'+aname+'||BSS',0,[]);
  2134. { add to group 'DGROUP' }
  2135. dgroup:=nil;
  2136. if assigned(internalObjData.GroupsList) then
  2137. dgroup:=TObjSectionGroup(internalObjData.GroupsList.Find('DGROUP'));
  2138. if dgroup=nil then
  2139. dgroup:=internalObjData.createsectiongroup('DGROUP');
  2140. SetLength(dgroup.members,Length(dgroup.members)+1);
  2141. dgroup.members[Length(dgroup.members)-1]:=internalObjData.CurrObjSec;
  2142. { define the symbol itself }
  2143. sym:=internalObjData.SymbolDefine(aname,AB_GLOBAL,AT_DATA);
  2144. sym.group:=dgroup;
  2145. end
  2146. else
  2147. inherited;
  2148. end;
  2149. procedure TMZExeOutput.DoRelocationFixup(objsec: TObjSection);
  2150. var
  2151. i: Integer;
  2152. omfsec: TOmfObjSection absolute objsec;
  2153. objreloc: TOmfRelocation;
  2154. target: DWord;
  2155. framebase: DWord;
  2156. fixupamount: Integer;
  2157. target_group: TMZExeUnifiedLogicalGroup;
  2158. procedure FixupOffset;
  2159. var
  2160. w: Word;
  2161. begin
  2162. omfsec.Data.seek(objreloc.DataOffset);
  2163. omfsec.Data.read(w,2);
  2164. w:=LEtoN(w);
  2165. Inc(w,fixupamount);
  2166. w:=LEtoN(w);
  2167. omfsec.Data.seek(objreloc.DataOffset);
  2168. omfsec.Data.write(w,2);
  2169. end;
  2170. procedure FixupBase;
  2171. var
  2172. w: Word;
  2173. begin
  2174. omfsec.Data.seek(objreloc.DataOffset);
  2175. omfsec.Data.read(w,2);
  2176. w:=LEtoN(w);
  2177. Inc(w,framebase shr 4);
  2178. w:=LEtoN(w);
  2179. omfsec.Data.seek(objreloc.DataOffset);
  2180. omfsec.Data.write(w,2);
  2181. Header.AddRelocation(omfsec.MZExeUnifiedLogicalSegment.MemBasePos shr 4,
  2182. omfsec.MemPos+objreloc.DataOffset-omfsec.MZExeUnifiedLogicalSegment.MemBasePos);
  2183. end;
  2184. begin
  2185. for i:=0 to objsec.ObjRelocations.Count-1 do
  2186. begin
  2187. objreloc:=TOmfRelocation(objsec.ObjRelocations[i]);
  2188. if assigned(objreloc.symbol) then
  2189. begin
  2190. target:=objreloc.symbol.address;
  2191. if objreloc.FrameGroup<>'' then
  2192. framebase:=TMZExeUnifiedLogicalGroup(ExeUnifiedLogicalGroups.Find(objreloc.FrameGroup)).MemPos
  2193. else if assigned(objreloc.symbol.group) then
  2194. framebase:=TMZExeUnifiedLogicalGroup(ExeUnifiedLogicalGroups.Find(objreloc.symbol.group.Name)).MemPos
  2195. else
  2196. framebase:=TOmfObjSection(objreloc.symbol.objsection).MZExeUnifiedLogicalSegment.MemBasePos;
  2197. case objreloc.typ of
  2198. RELOC_ABSOLUTE,RELOC_SEG:
  2199. fixupamount:=target-framebase;
  2200. RELOC_RELATIVE,RELOC_SEGREL:
  2201. fixupamount:=target-(omfsec.MemPos+objreloc.DataOffset)-2;
  2202. else
  2203. internalerror(2015082402);
  2204. end;
  2205. case objreloc.typ of
  2206. RELOC_ABSOLUTE,
  2207. RELOC_RELATIVE:
  2208. FixupOffset;
  2209. RELOC_SEG,
  2210. RELOC_SEGREL:
  2211. FixupBase;
  2212. else
  2213. internalerror(2015082403);
  2214. end;
  2215. end
  2216. else if assigned(objreloc.objsection) then
  2217. begin
  2218. target:=objreloc.objsection.MemPos;
  2219. if objreloc.FrameGroup<>'' then
  2220. framebase:=TMZExeUnifiedLogicalGroup(ExeUnifiedLogicalGroups.Find(objreloc.FrameGroup)).MemPos
  2221. else
  2222. framebase:=TOmfObjSection(objreloc.objsection).MZExeUnifiedLogicalSegment.MemBasePos;
  2223. case objreloc.typ of
  2224. RELOC_ABSOLUTE,RELOC_SEG:
  2225. fixupamount:=target-framebase;
  2226. RELOC_RELATIVE,RELOC_SEGREL:
  2227. fixupamount:=target-(omfsec.MemPos+objreloc.DataOffset)-2;
  2228. else
  2229. internalerror(2015082405);
  2230. end;
  2231. case objreloc.typ of
  2232. RELOC_ABSOLUTE,
  2233. RELOC_RELATIVE:
  2234. FixupOffset;
  2235. RELOC_SEG,
  2236. RELOC_SEGREL:
  2237. FixupBase;
  2238. else
  2239. internalerror(2015082406);
  2240. end;
  2241. end
  2242. else if objreloc.typ in [RELOC_DGROUP,RELOC_DGROUPREL] then
  2243. begin
  2244. target_group:=TMZExeUnifiedLogicalGroup(ExeUnifiedLogicalGroups.Find('DGROUP'));
  2245. target:=target_group.MemPos;
  2246. if objreloc.FrameGroup<>'' then
  2247. framebase:=TMZExeUnifiedLogicalGroup(ExeUnifiedLogicalGroups.Find(objreloc.FrameGroup)).MemPos
  2248. else
  2249. framebase:=target_group.MemPos;
  2250. case objreloc.typ of
  2251. RELOC_DGROUP:
  2252. fixupamount:=target-framebase;
  2253. RELOC_DGROUPREL:
  2254. fixupamount:=target-(omfsec.MemPos+objreloc.DataOffset)-2;
  2255. else
  2256. internalerror(2015082408);
  2257. end;
  2258. case objreloc.typ of
  2259. RELOC_DGROUP,
  2260. RELOC_DGROUPREL:
  2261. FixupBase;
  2262. else
  2263. internalerror(2015082406);
  2264. end;
  2265. end
  2266. else
  2267. internalerror(2015082407);
  2268. end;
  2269. end;
  2270. function IOmfObjSectionClassNameCompare(Item1, Item2: Pointer): Integer;
  2271. var
  2272. I1 : TOmfObjSection absolute Item1;
  2273. I2 : TOmfObjSection absolute Item2;
  2274. begin
  2275. Result:=CompareStr(I1.ClassName,I2.ClassName);
  2276. if Result=0 then
  2277. Result:=CompareStr(I1.Name,I2.Name);
  2278. if Result=0 then
  2279. Result:=I1.SortOrder-I2.SortOrder;
  2280. end;
  2281. procedure TMZExeOutput.Order_ObjSectionList(ObjSectionList: TFPObjectList; const aPattern: string);
  2282. var
  2283. i: Integer;
  2284. begin
  2285. for i:=0 to ObjSectionList.Count-1 do
  2286. TOmfObjSection(ObjSectionList[i]).SortOrder:=i;
  2287. ObjSectionList.Sort(@IOmfObjSectionClassNameCompare);
  2288. end;
  2289. procedure TMZExeOutput.MemPos_EndExeSection;
  2290. var
  2291. SecName: TSymStr='';
  2292. begin
  2293. if assigned(CurrExeSec) then
  2294. SecName:=CurrExeSec.Name;
  2295. inherited MemPos_EndExeSection;
  2296. if SecName='.MZ_flat_content' then
  2297. begin
  2298. CalcExeUnifiedLogicalSegments;
  2299. CalcExeGroups;
  2300. CalcSegments_MemBasePos;
  2301. if assigned(exemap) then
  2302. WriteMap_SegmentsAndGroups;
  2303. end;
  2304. end;
  2305. function TMZExeOutput.writeData: boolean;
  2306. begin
  2307. if apptype=app_com then
  2308. Result:=WriteCom
  2309. else
  2310. Result:=WriteExe;
  2311. end;
  2312. constructor TMZExeOutput.create;
  2313. begin
  2314. inherited create;
  2315. CExeSection:=TMZExeSection;
  2316. CObjData:=TOmfObjData;
  2317. CObjSymbol:=TOmfObjSymbol;
  2318. { "640K ought to be enough for anybody" :) }
  2319. MaxMemPos:=$9FFFF;
  2320. FExeUnifiedLogicalSegments:=TFPHashObjectList.Create;
  2321. FExeUnifiedLogicalGroups:=TFPHashObjectList.Create;
  2322. FHeader:=TMZExeHeader.Create;
  2323. end;
  2324. destructor TMZExeOutput.destroy;
  2325. begin
  2326. FHeader.Free;
  2327. FExeUnifiedLogicalGroups.Free;
  2328. FExeUnifiedLogicalSegments.Free;
  2329. inherited destroy;
  2330. end;
  2331. {****************************************************************************
  2332. TOmfAssembler
  2333. ****************************************************************************}
  2334. constructor TOmfAssembler.Create(smart:boolean);
  2335. begin
  2336. inherited Create(smart);
  2337. CObjOutput:=TOmfObjOutput;
  2338. CInternalAr:=TOmfLibObjectWriter;
  2339. end;
  2340. {*****************************************************************************
  2341. Initialize
  2342. *****************************************************************************}
  2343. {$ifdef i8086}
  2344. const
  2345. as_i8086_omf_info : tasminfo =
  2346. (
  2347. id : as_i8086_omf;
  2348. idtxt : 'OMF';
  2349. asmbin : '';
  2350. asmcmd : '';
  2351. supported_targets : [system_i8086_msdos];
  2352. flags : [af_outputbinary,af_no_debug];
  2353. labelprefix : '..@';
  2354. comment : '; ';
  2355. dollarsign: '$';
  2356. );
  2357. {$endif i8086}
  2358. initialization
  2359. {$ifdef i8086}
  2360. RegisterAssembler(as_i8086_omf_info,TOmfAssembler);
  2361. {$endif i8086}
  2362. end.