ogomf.pas 93 KB

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