machowriter.pp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2008 by Giulio Bernardi
  4. Resource writer for Mach-O files
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {$IFNDEF FPC_DOTTEDUNITS}
  12. unit machowriter;
  13. {$ENDIF FPC_DOTTEDUNITS}
  14. {$MODE OBJFPC} {$H+}
  15. interface
  16. {$IFDEF FPC_DOTTEDUNITS}
  17. uses
  18. System.Classes, System.SysUtils, System.Resources.Resource, System.Resources.Macho.Types;
  19. {$ELSE FPC_DOTTEDUNITS}
  20. uses
  21. Classes, SysUtils, resource, machotypes;
  22. {$ENDIF FPC_DOTTEDUNITS}
  23. type
  24. EMachOResourceWriterException = class(EResourceWriterException);
  25. EMachOResourceWriterUnknownBitSizeException = class(EMachOResourceWriterException);
  26. EMachOResourceWriterSymbolTableWrongOrderException = class(EMachOResourceWriterException);
  27. type
  28. { TMachOResourceWriter }
  29. TMachOResourceWriter = class(TAbstractResourceWriter)
  30. private
  31. fExtensions : string;
  32. fDescription : string;
  33. fNativeEndianess : integer;
  34. fEndianess : integer;
  35. fOppositeEndianess : boolean;
  36. fMachineType : TMachOMachineType;
  37. fSubMachineType : TMachoSubMachineType;
  38. fBits : integer;
  39. procedure SetDefaultTarget;
  40. procedure SetMachineType(const aMachineType : TMachOMachineType);
  41. procedure SetSubMachineType(const aSubMachineType: TMachoSubMachineType);
  42. protected
  43. function GetExtensions : string; override;
  44. function GetDescription : string; override;
  45. procedure Write(aResources : TResources; aStream : TStream); override;
  46. public
  47. constructor Create; override;
  48. destructor Destroy; override;
  49. property MachineType : TMachOMachineType read fMachineType write SetMachineType;
  50. property SubMachineType : TMachOSubMachineType read fSubMachineType write SetSubMachineType;
  51. end;
  52. implementation
  53. {$IFDEF FPC_DOTTEDUNITS}
  54. uses System.Resources.Tree, System.Resources.Macho.Consts, System.Resources.StringTable.Types, System.Resources.Types;
  55. {$ELSE FPC_DOTTEDUNITS}
  56. uses resourcetree, machoconsts, strtable, fpcrestypes;
  57. {$ENDIF FPC_DOTTEDUNITS}
  58. type
  59. { TMachORelocations }
  60. TMachORelocations = class
  61. private
  62. fList : TFPList;
  63. fStartOfs : longword;
  64. fOppositeEndianess : boolean;
  65. fEndianess : integer;
  66. fRelocType : longword;
  67. fRelocSize : longword;
  68. function GetCount : integer;
  69. protected
  70. public
  71. constructor Create(aMachineType : TMachOMachineType; aOppositeEndianess : boolean);
  72. destructor Destroy; override;
  73. procedure Add(addr: longword; symnum: longword);
  74. procedure Clear;
  75. procedure WriteToStream(aStream : TStream);
  76. property Count : integer read GetCount;
  77. property StartOfs : longword read fStartOfs write fStartOfs;
  78. end;
  79. { TMachOSymbolTable }
  80. TMachOSymbolTable = class
  81. protected
  82. fStringTable : TObjectStringTable;
  83. fList : TFPList;
  84. fStartOfs : longword;
  85. fLocalCount : integer;
  86. fGlobalCount : integer;
  87. fOppositeEndianess : boolean;
  88. function GetCount : integer;
  89. function AddSymbol(aName : string; sect : byte; addr : longword;
  90. glob, undef : boolean) : integer; virtual; abstract;
  91. protected
  92. public
  93. constructor Create(aStringTable : TObjectStringTable);
  94. destructor Destroy; override;
  95. function AddLocal(const aName : string; sect : byte; addr : longword) : integer;
  96. function AddGlobal(const aName : string; sect : byte; addr : longword) : integer;
  97. function AddExternal(const aName : string) : integer;
  98. procedure Clear;
  99. procedure WriteToStream(aStream : TStream); virtual; abstract;
  100. procedure SetSymbolOffset(symbolnum : integer; offset: longword); virtual; abstract;
  101. property Count : integer read GetCount;
  102. property LocalCount : integer read fLocalCount;
  103. property GlobalCount : integer read fGlobalCount;
  104. property StartOfs : longword read fStartOfs write fStartOfs;
  105. property OppositeEndianess : boolean read fOppositeEndianess write fOppositeEndianess;
  106. end;
  107. { TAbstractMachOSubWriter }
  108. TAbstractMachOSubWriter = class
  109. protected
  110. fParent : TMachOResourceWriter;
  111. fOppositeEndianess : boolean;
  112. fMachineType : TMachOMachineType;
  113. fSubMachineType: TMachoSubMachineType;
  114. fDataAlignment : integer;
  115. fSectAlignment : integer;
  116. fSegType : longword;
  117. fHeader : TMachHdr;
  118. fMachOStringTable : TObjectStringTable;
  119. fSymbolTable : TMachOSymbolTable;
  120. fRelocations : TMachORelocations;
  121. fRoot : TRootResTreeNode;
  122. fResStrTable : TResStringTable;
  123. fCurOfs : longword;
  124. fDataCurOfs : longword;
  125. fSectionStart : longword;
  126. ffpcresourcessym,
  127. ffpcreshandlessym : integer;
  128. function NextAligned(aBound, aValue : longword) : longword;
  129. procedure Align(aBound : integer; aStream : TStream);
  130. procedure PrescanResourceTree; virtual; abstract;
  131. function PrescanNode(aNode : TResourceTreeNode; aNodeSize : longword) : longword;
  132. procedure WriteEmptyMachOHeader(aStream : TStream);
  133. procedure WriteResHeader(aStream : TStream; aResources : TResources); virtual; abstract;
  134. procedure WriteNodeInfos(aStream : TStream); virtual; abstract;
  135. procedure WriteNodeInfo(aStream : TStream; aNode : TResourceTreeNode); virtual; abstract;
  136. procedure WriteSubNodes(aStream : TStream; aNode : TResourceTreeNode);
  137. procedure WriteResStringTable(aStream : TStream);
  138. procedure WriteRawData(aStream : TStream);
  139. procedure WriteResData(aStream : TStream; aNode : TResourceTreeNode);
  140. procedure WriteRelocations(aStream : TStream);
  141. procedure WriteSymbolTable(aStream : TStream);
  142. procedure WriteMachOStringTable(aStream : TStream);
  143. procedure AllocateSpaceForLoadCommands(aStream : TStream); virtual; abstract;
  144. procedure FixHeader(aStream : TStream);
  145. procedure FixLoadCommands(aStream : TStream; aResources : TResources); virtual; abstract;
  146. procedure FixResHeader(aStream : TStream); virtual; abstract;
  147. procedure Write(aResources: TResources; aStream: TStream);
  148. public
  149. constructor Create(aParent : TMachOResourceWriter; const aMachineType
  150. : TMachOMachineType; const aSubMachineType: TMachoSubMachineType;
  151. const aOppositeEndianess : boolean); virtual;
  152. destructor Destroy; override;
  153. end;
  154. (*
  155. Almost all differences in 32 and 64 bit mach-o files lie in record sizes.
  156. Generics don't work with record types, so use macros to do this task
  157. (uglier, but should be the same)
  158. *)
  159. {$MACRO ON}
  160. //Define TMachO32SymbolTable and TMachO32SubWriter
  161. {$DEFINE _TMachOSymbolTable_:=TMachO32SymbolTable}
  162. {$DEFINE _TMachOSubWriter_:=TMachO32SubWriter}
  163. {$DEFINE _TNlist_:=TNlist32}
  164. {$DEFINE _PNList_:=PNList32}
  165. {$DEFINE _TResHdr_:=TResHdr32}
  166. {$DEFINE _TResInfoNode_:=TResInfoNode32}
  167. {$DEFINE _TSegmentCommand_:=TSegmentCommand32}
  168. {$DEFINE _TSection_:=TSection32}
  169. {$DEFINE _ptrtype_:=longword}
  170. {$INCLUDE machosubwriter.inc}
  171. //Define TMachO64SymbolTable and TMachO64SubWriter
  172. {$DEFINE _TMachOSymbolTable_:=TMachO64SymbolTable}
  173. {$DEFINE _TMachOSubWriter_:=TMachO64SubWriter}
  174. {$DEFINE _TNlist_:=TNlist64}
  175. {$DEFINE _PNList_:=PNList64}
  176. {$DEFINE _TResHdr_:=TResHdr64}
  177. {$DEFINE _TResInfoNode_:=TResInfoNode64}
  178. {$DEFINE _TSegmentCommand_:=TSegmentCommand64}
  179. {$DEFINE _TSection_:=TSection64}
  180. {$DEFINE _ptrtype_:=qword}
  181. {$INCLUDE machosubwriter.inc}
  182. //Clean all this stuff...
  183. {$UNDEF _TMachOSymbolTable_}
  184. {$UNDEF _TMachOSubWriter_}
  185. {$UNDEF _TNlist_}
  186. {$UNDEF _PNList_}
  187. {$UNDEF _TResHdr_}
  188. {$UNDEF _TResInfoNode_}
  189. {$UNDEF _TSegmentCommand_}
  190. {$UNDEF _TSection_}
  191. { TMachOSymbolTable }
  192. function TMachOSymbolTable.GetCount: integer;
  193. begin
  194. Result:=fList.Count;
  195. end;
  196. constructor TMachOSymbolTable.Create(aStringTable: TObjectStringTable);
  197. begin
  198. fStringTable:=aStringTable;
  199. fList:=TFPList.Create;
  200. fStartOfs:=0;
  201. fLocalCount:=0;
  202. fGlobalCount:=0;
  203. fOppositeEndianess:=false;
  204. end;
  205. destructor TMachOSymbolTable.Destroy;
  206. begin
  207. Clear;
  208. fList.Free;
  209. end;
  210. function TMachOSymbolTable.AddLocal(const aName: string; sect: byte; addr: longword
  211. ): integer;
  212. begin
  213. Result:=AddSymbol(aName,sect,addr,false,false);
  214. inc(fLocalCount);
  215. end;
  216. function TMachOSymbolTable.AddGlobal(const aName: string; sect: byte; addr: longword
  217. ): integer;
  218. begin
  219. Result:=AddSymbol(aName,sect,addr,true,false);
  220. inc(fGlobalCount);
  221. end;
  222. function TMachOSymbolTable.AddExternal(const aName: string): integer;
  223. begin
  224. Result:=AddSymbol(aName,NO_SECT,0,false,true);
  225. inc(fGlobalCount);
  226. end;
  227. procedure TMachOSymbolTable.Clear;
  228. var i : integer;
  229. begin
  230. for i:=0 to fList.Count-1 do
  231. FreeMem(fList[i]);
  232. fList.Clear;
  233. end;
  234. { TMachORelocations }
  235. function TMachORelocations.GetCount: integer;
  236. begin
  237. Result:=fList.Count;
  238. end;
  239. constructor TMachORelocations.Create(aMachineType : TMachOMachineType;
  240. aOppositeEndianess : boolean);
  241. begin
  242. fList:=TFPList.Create;
  243. fStartOfs:=0;
  244. case aMachineType of
  245. mmtpowerpc : begin
  246. fEndianess:=MACH_BIG_ENDIAN;
  247. fRelocType:=PPC_RELOC_VANILLA;
  248. fRelocSize:=2;
  249. end;
  250. mmtpowerpc64 : begin
  251. fEndianess:=MACH_BIG_ENDIAN;
  252. fRelocType:=PPC_RELOC_VANILLA;
  253. fRelocSize:=3;
  254. end;
  255. mmti386 : begin
  256. fEndianess:=MACH_LITTLE_ENDIAN;
  257. fRelocType:=GENERIC_RELOC_VANILLA;
  258. fRelocSize:=2;
  259. end;
  260. mmtx86_64 : begin
  261. fEndianess:=MACH_LITTLE_ENDIAN;
  262. fRelocType:=X86_64_RELOC_UNSIGNED;
  263. fRelocSize:=3;
  264. end;
  265. mmtarm : begin
  266. fEndianess:=MACH_LITTLE_ENDIAN;
  267. fRelocType:=ARM_RELOC_VANILLA;
  268. fRelocSize:=2;
  269. end;
  270. mmtarm64 : begin
  271. fEndianess:=MACH_LITTLE_ENDIAN;
  272. fRelocType:=ARM64_RELOC_UNSIGNED;
  273. fRelocSize:=3;
  274. end;
  275. end;
  276. fOppositeEndianess:=aOppositeEndianess;
  277. end;
  278. destructor TMachORelocations.Destroy;
  279. begin
  280. Clear;
  281. fList.Free;
  282. end;
  283. procedure TMachORelocations.Add(addr: longword; symnum: longword);
  284. var p : PRelocationInfo;
  285. begin
  286. p:=GetMem(sizeof(TRelocationInfo));
  287. p^.address:=addr;
  288. //bit fields make things difficult...
  289. if fEndianess=MACH_BIG_ENDIAN then
  290. begin
  291. p^.flags:=symnum shl 8;
  292. p^.flags:=p^.flags or (fRelocSize shl 5); //length
  293. p^.flags:=p^.flags or fRelocType;
  294. { reference via symbol }
  295. p^.flags:=p^.flags or R_EXTERN_BE;
  296. end
  297. else
  298. begin
  299. p^.flags:=symnum and R_SYMBOLNUM_LE;
  300. p^.flags:=p^.flags or (fRelocSize shl 25); //length
  301. p^.flags:=p^.flags or (fRelocType shl 28);
  302. { reference via symbol }
  303. p^.flags:=p^.flags or R_EXTERN_LE;
  304. end;
  305. fList.Add(p);
  306. end;
  307. procedure TMachORelocations.Clear;
  308. var i : integer;
  309. begin
  310. for i:=0 to fList.Count-1 do
  311. FreeMem(PRelocationInfo(fList[i]));
  312. fList.Clear;
  313. end;
  314. procedure TMachORelocations.WriteToStream(aStream: TStream);
  315. var rel : TRelocationInfo;
  316. i : integer;
  317. begin
  318. for i:=0 to fList.Count-1 do
  319. begin
  320. rel:=PRelocationInfo(fList[i])^;
  321. if fOppositeEndianess then
  322. begin
  323. rel.address:=SwapEndian(rel.address);
  324. rel.flags:=SwapEndian(rel.flags);
  325. end;
  326. aStream.WriteBuffer(rel,sizeof(rel));
  327. end;
  328. end;
  329. { TAbstractMachOSubWriter }
  330. function TAbstractMachOSubWriter.NextAligned(aBound, aValue: longword): longword;
  331. var topad : longword;
  332. begin
  333. Result:=aValue;
  334. topad:=aBound-(aValue mod aBound);
  335. if topad<>aBound then inc(Result,topad);
  336. end;
  337. procedure TAbstractMachOSubWriter.Align(aBound: integer; aStream: TStream);
  338. var topad,tmp : integer;
  339. qw : qword;
  340. begin
  341. qw:=0;
  342. topad:=aBound-(aStream.Position mod aBound);
  343. if topad<>aBound then
  344. while topad>0 do
  345. begin
  346. if topad>8 then tmp:=8 else tmp:=topad;
  347. aStream.WriteBuffer(qw,tmp);
  348. dec(topad,tmp);
  349. end;
  350. end;
  351. function TAbstractMachOSubWriter.PrescanNode(aNode: TResourceTreeNode;
  352. aNodeSize : longword): longword;
  353. var curofs : longword;
  354. i : integer;
  355. subnode : TResourceTreeNode;
  356. begin
  357. if aNode.IsLeaf then
  358. begin
  359. Result:=aNode.SubDirRVA;
  360. exit;
  361. end;
  362. if aNode.Desc.DescType=dtName then
  363. aNode.NameRVA:=fResStrTable.Add(aNode.Desc.Name);
  364. //first node subnodes begin at curofs (after all node headers)
  365. curofs:=aNode.SubDirRva+(aNode.NamedCount+aNode.IDCount)*aNodeSize;
  366. for i:=0 to aNode.NamedCount-1 do
  367. begin
  368. subnode:=aNode.NamedEntries[i];
  369. subnode.SubDirRVA:=curofs;
  370. curofs:=PrescanNode(subnode,aNodeSize);
  371. end;
  372. for i:=0 to aNode.IDCount-1 do
  373. begin
  374. subnode:=aNode.IDEntries[i];
  375. subnode.SubDirRVA:=curofs;
  376. curofs:=PrescanNode(subnode,aNodeSize);
  377. end;
  378. Result:=curofs;
  379. end;
  380. procedure TAbstractMachOSubWriter.WriteEmptyMachOHeader(aStream: TStream);
  381. begin
  382. FillByte(fHeader,sizeof(TMachHdr),0);
  383. aStream.WriteBuffer(fHeader,sizeof(TMachHdr));
  384. Align(fDataAlignment,aStream);
  385. end;
  386. procedure TAbstractMachOSubWriter.WriteSubNodes(aStream: TStream;
  387. aNode: TResourceTreeNode);
  388. var i : integer;
  389. begin
  390. for i:=0 to aNode.NamedCount-1 do
  391. WriteNodeInfo(aStream,aNode.NamedEntries[i]);
  392. for i:=0 to aNode.IDCount-1 do
  393. WriteNodeInfo(aStream,aNode.IDEntries[i]);
  394. for i:=0 to aNode.NamedCount-1 do
  395. WriteSubNodes(aStream,aNode.NamedEntries[i]);
  396. for i:=0 to aNode.IDCount-1 do
  397. WriteSubNodes(aStream,aNode.IDEntries[i]);
  398. end;
  399. procedure TAbstractMachOSubWriter.WriteResStringTable(aStream: TStream);
  400. begin
  401. if fResStrTable.Used then
  402. fResStrTable.WriteToStream(aStream);
  403. Align(fDataAlignment,aStream);
  404. end;
  405. procedure TAbstractMachOSubWriter.WriteRawData(aStream: TStream);
  406. begin
  407. WriteResData(aStream,fRoot);
  408. end;
  409. procedure TAbstractMachOSubWriter.WriteResData(aStream: TStream;
  410. aNode: TResourceTreeNode);
  411. var rawdata : TStream;
  412. i : integer;
  413. begin
  414. if aNode.IsLeaf then
  415. begin
  416. rawdata:=aNode.Data.RawData;
  417. rawdata.Position:=0;
  418. aStream.CopyFrom(rawdata,rawdata.Size);
  419. Align(fDataAlignment,aStream);
  420. exit;
  421. end;
  422. for i:=0 to aNode.NamedCount-1 do
  423. WriteResData(aStream,aNode.NamedEntries[i]);
  424. for i:=0 to aNode.IDCount-1 do
  425. WriteResData(aStream,aNode.IDEntries[i]);
  426. end;
  427. procedure TAbstractMachOSubWriter.WriteRelocations(aStream: TStream);
  428. begin
  429. fRelocations.WriteToStream(aStream);
  430. end;
  431. procedure TAbstractMachOSubWriter.WriteSymbolTable(aStream: TStream);
  432. begin
  433. fSymbolTable.WriteToStream(aStream);
  434. end;
  435. procedure TAbstractMachOSubWriter.WriteMachOStringTable(aStream: TStream);
  436. begin
  437. fMachOStringTable.WriteToStream(aStream);
  438. Align(fDataAlignment,aStream);
  439. end;
  440. procedure TAbstractMachOSubWriter.FixHeader(aStream: TStream);
  441. const
  442. ppcsm2int: array[TMachOSubMachineTypePowerPC] of longint = (CPU_SUBTYPE_POWERPC_ALL, CPU_SUBTYPE_POWERPC_7400, CPU_SUBTYPE_POWERPC_7450, CPU_SUBTYPE_POWERPC_970);
  443. ppc64sm2int: array[TMachOSubMachineTypePowerPC64] of longint = (CPU_SUBTYPE_POWERPC_ALL);
  444. i386sm2int: array[TMachOSubMachineType386] of longint = (CPU_SUBTYPE_I386_ALL);
  445. x86_64sm2int: array[TMachOSubMachineTypex64] of longint = (CPU_SUBTYPE_X86_64_ALL, CPU_SUBTYPE_X86_64_H);
  446. armsm2int: array[TMachOSubMachineTypeArm] of longint = (CPU_SUBTYPE_ARM_ALL,
  447. CPU_SUBTYPE_ARM_V4T,CPU_SUBTYPE_ARM_V6,CPU_SUBTYPE_ARM_V5TEJ,
  448. CPU_SUBTYPE_ARM_XSCALE,CPU_SUBTYPE_ARM_V7);
  449. arm64sm2int: array[TMachOSubMachineTypeAarch64] of longint = (CPU_SUBTYPE_ARM64_ALL, CPU_SUBTYPE_ARM64_V8, CPU_SUBTYPE_ARM64E);
  450. begin
  451. aStream.Position:=0;
  452. case fMachineType of
  453. mmtpowerpc : begin
  454. fHeader.magic:=MH_MAGIC;
  455. fHeader.cputype:=CPU_TYPE_POWERPC;
  456. fHeader.cpusubtype:=ppcsm2int[fSubMachineType.fPpcSubType];
  457. end;
  458. mmtpowerpc64 : begin
  459. fHeader.magic:=MH_MAGIC_64;
  460. fHeader.cputype:=CPU_TYPE_POWERPC64;
  461. fHeader.cpusubtype:=ppc64sm2int[fSubMachineType.fPpc64SubType];
  462. end;
  463. mmti386 : begin
  464. fHeader.magic:=MH_MAGIC;
  465. fHeader.cputype:=CPU_TYPE_I386;
  466. fHeader.cpusubtype:=i386sm2int[fSubMachineType.f386SubType];
  467. end;
  468. mmtx86_64 : begin
  469. fHeader.magic:=MH_MAGIC_64;
  470. fHeader.cputype:=CPU_TYPE_X86_64;
  471. fHeader.cpusubtype:=x86_64sm2int[fSubMachineType.fX64SubType];
  472. end;
  473. mmtarm : begin
  474. fHeader.magic:=MH_MAGIC;
  475. fHeader.cputype:=CPU_TYPE_ARM;
  476. fHeader.cpusubtype:=armsm2int[fSubMachineType.fArmSubType];
  477. end;
  478. mmtarm64 : begin
  479. fHeader.magic:=MH_MAGIC_64;
  480. fHeader.cputype:=CPU_TYPE_ARM64;
  481. fHeader.cpusubtype:=arm64sm2int[fSubMachineType.fArm64SubType];
  482. end;
  483. end;
  484. fHeader.filetype:=MH_OBJECT;
  485. fHeader.ncmds:=3;
  486. fHeader.flags:=0;
  487. if fOppositeEndianess then
  488. begin
  489. fHeader.magic:=SwapEndian(fHeader.magic);
  490. fHeader.cputype:=SwapEndian(fHeader.cputype);
  491. fHeader.cpusubtype:=SwapEndian(fHeader.cpusubtype);
  492. fHeader.filetype:=SwapEndian(fHeader.filetype);
  493. fHeader.ncmds:=SwapEndian(fHeader.ncmds);
  494. fHeader.sizeofcmds:=SwapEndian(fHeader.sizeofcmds);
  495. fHeader.flags:=SwapEndian(fHeader.flags);
  496. end;
  497. aStream.WriteBuffer(fHeader,sizeof(fHeader));
  498. Align(fDataAlignment,aStream);
  499. end;
  500. procedure TAbstractMachOSubWriter.Write(aResources: TResources; aStream: TStream);
  501. begin
  502. WriteEmptyMachOHeader(aStream);
  503. AllocateSpaceForLoadCommands(aStream);
  504. fSectionStart:=aStream.Position;
  505. fRoot:=TRootResTreeNode(fParent.GetTree(aResources));
  506. { on AArch64, if you want to refer to a section from another one, you
  507. have to do it via an explicit symbol reference.
  508. }
  509. { dummy text section symbol }
  510. fSymbolTable.AddLocal('ltmp0',1,0);
  511. { dummy fpc.resources symbol }
  512. fSymbolTable.AddLocal('ltmp1',2,0);
  513. { the offset needs to be the offset in the file, *not* relative to the start
  514. of the section. We don't know here yet how large the fpcresources section
  515. will be -> fix up later }
  516. ffpcreshandlessym:=fSymbolTable.AddGlobal('__fpc_reshandles_internal',3,0);
  517. { don't add this before any local symbols, as local symbols must be written
  518. first. We can't reorder while writing the symbol table, because we already
  519. need the symbol numbers above }
  520. ffpcresourcessym:=fSymbolTable.AddGlobal('FPC_RESSYMBOL',2,0);
  521. PrescanResourceTree;
  522. WriteResHeader(aStream,aResources);
  523. WriteNodeInfos(aStream);
  524. WriteResStringTable(aStream);
  525. WriteRawData(aStream);
  526. fRelocations.StartOfs:=aStream.Position;
  527. WriteRelocations(aStream);
  528. { fix up offset of fpcreshandles symbol }
  529. fSymbolTable.SetSymbolOffset(ffpcreshandlessym,fDataCurOfs);
  530. fSymbolTable.StartOfs:=aStream.Position;
  531. WriteSymbolTable(aStream);
  532. fMachOStringTable.StartOfs:=aStream.Position;
  533. WriteMachOStringTable(aStream);
  534. FixHeader(aStream);
  535. FixLoadCommands(aStream,aResources);
  536. end;
  537. constructor TAbstractMachOSubWriter.Create(aParent : TMachOResourceWriter;
  538. const aMachineType : TMachOMachineType; const aSubMachineType:
  539. TMachoSubMachineType; const aOppositeEndianess : boolean);
  540. begin
  541. fParent:=aParent;
  542. fMachineType:=aMachineType;
  543. fSubMachineType:=aSubMachineType;
  544. fOppositeEndianess:=aOppositeEndianess;
  545. fRoot:=nil;
  546. fMachOStringTable:=TObjectStringTable.Create(nil,0);
  547. fRelocations:=TMachORelocations.Create(fMachineType,fOppositeEndianess);
  548. fResStrTable:=TResStringTable.Create;
  549. fCurOfs:=0;
  550. fDataCurOfs:=0;
  551. fSectionStart:=0;
  552. end;
  553. destructor TAbstractMachOSubWriter.Destroy;
  554. begin
  555. fSymbolTable.Free;
  556. fResStrTable.Free;
  557. fRelocations.Free;
  558. fMachOStringTable.Free;
  559. end;
  560. { TMachOResourceWriter }
  561. procedure TMachOResourceWriter.SetDefaultTarget;
  562. begin
  563. {$INCLUDE machodefaulttarget.inc}
  564. end;
  565. procedure TMachOResourceWriter.SetMachineType(const aMachineType: TMachOMachineType);
  566. begin
  567. case aMachineType of
  568. mmtpowerpc : begin fBits:=MACH_32BIT; fEndianess:=MACH_BIG_ENDIAN; end;
  569. mmtpowerpc64 : begin fBits:=MACH_64BIT; fEndianess:=MACH_BIG_ENDIAN; end;
  570. mmti386 : begin fBits:=MACH_32BIT; fEndianess:=MACH_LITTLE_ENDIAN; end;
  571. mmtx86_64 : begin fBits:=MACH_64BIT; fEndianess:=MACH_LITTLE_ENDIAN; end;
  572. mmtarm : begin fBits:=MACH_32BIT; fEndianess:=MACH_LITTLE_ENDIAN; end;
  573. mmtarm64 : begin fBits:=MACH_64BIT; fEndianess:=MACH_LITTLE_ENDIAN; end;
  574. end;
  575. fMachineType:=aMachineType;
  576. fOppositeEndianess:=fNativeEndianess<>fEndianess;
  577. end;
  578. procedure TMachOResourceWriter.SetSubMachineType(const aSubMachineType: TMachoSubMachineType);
  579. begin
  580. fSubMachineType:=aSubMachineType;
  581. end;
  582. function TMachOResourceWriter.GetExtensions: string;
  583. begin
  584. Result:=fExtensions;
  585. end;
  586. function TMachOResourceWriter.GetDescription: string;
  587. begin
  588. Result:=fDescription;
  589. end;
  590. procedure TMachOResourceWriter.Write(aResources: TResources; aStream: TStream);
  591. var subwriter : TAbstractMachOSubWriter;
  592. begin
  593. case fBits of
  594. MACH_32BIT : subwriter:=TMachO32SubWriter.Create(self,fMachineType,fSubMachineType,fOppositeEndianess);
  595. MACH_64BIT : subwriter:=TMachO64SubWriter.Create(self,fMachineType,fSubMachineType,fOppositeEndianess)
  596. else
  597. raise EMachOResourceWriterUnknownBitSizeException.Create('');
  598. end;
  599. try
  600. subwriter.Write(aResources,aStream);
  601. finally
  602. subwriter.Free;
  603. end;
  604. end;
  605. constructor TMachOResourceWriter.Create;
  606. begin
  607. fExtensions:='.o .or';
  608. fDescription:='Mach-O resource writer';
  609. SetDefaultTarget;
  610. end;
  611. destructor TMachOResourceWriter.Destroy;
  612. begin
  613. end;
  614. initialization
  615. TResources.RegisterWriter('.o',TMachOResourceWriter);
  616. TResources.RegisterWriter('.or',TMachOResourceWriter);
  617. end.