ogomf.pas 92 KB

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