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