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