فهرست منبع

* initial version of internal Mach-O/i386 assembler by Dmitry Boyarintsev
(mantis #15163)

git-svn-id: trunk@14628 -

Jonas Maebe 15 سال پیش
والد
کامیت
28cd8271c9

+ 3 - 0
.gitattributes

@@ -234,6 +234,8 @@ compiler/m68k/r68ksup.inc svneol=native#text/plain
 compiler/m68k/ra68k.pas svneol=native#text/plain
 compiler/m68k/ra68kmot.pas svneol=native#text/plain
 compiler/m68k/rgcpu.pas svneol=native#text/plain
+compiler/macho.pas svneol=native#text/plain
+compiler/machoutils.pas svneol=native#text/plain
 compiler/mips/aasmcpu.pas svneol=native#text/plain
 compiler/mips/aoptcpu.pas svneol=native#text/plain
 compiler/mips/aoptcpub.pas svneol=native#text/plain
@@ -330,6 +332,7 @@ compiler/ogbase.pas svneol=native#text/plain
 compiler/ogcoff.pas svneol=native#text/plain
 compiler/ogelf.pas svneol=native#text/plain
 compiler/oglx.pas svneol=native#text/plain
+compiler/ogmacho.pas svneol=native#text/plain
 compiler/ogmap.pas svneol=native#text/plain
 compiler/optbase.pas svneol=native#text/plain
 compiler/optcse.pas svneol=native#text/plain

+ 1 - 1
compiler/aasmbase.pas

@@ -40,7 +40,7 @@ interface
        TAsmsymbind=(
          AB_NONE,AB_EXTERNAL,AB_COMMON,AB_LOCAL,AB_GLOBAL,AB_WEAK_EXTERNAL,
          { global in the current program/library, but not visible outside it }
-         AB_PRIVATE_EXTERN);
+         AB_PRIVATE_EXTERN,AB_LAZY);
 
        TAsmsymtype=(
          AT_NONE,AT_FUNCTION,AT_DATA,AT_SECTION,AT_LABEL,

+ 75 - 3
compiler/assemble.pas

@@ -131,6 +131,8 @@ interface
         procedure MakeObject;override;
       end;
 
+      { TInternalAssembler }
+
       TInternalAssembler=class(TAssembler)
       private
         FCObjOutput : TObjOutputclass;
@@ -142,6 +144,7 @@ interface
         currlist     : TAsmList;
         procedure WriteStab(p:pchar);
         function  MaybeNextList(var hp:Tai):boolean;
+        function  SetIndirectToSymbol(hp: Tai; const indirectname: string): Boolean;
         function  TreePass0(hp:Tai):Tai;
         function  TreePass1(hp:Tai):Tai;
         function  TreePass2(hp:Tai):Tai;
@@ -925,6 +928,33 @@ Implementation
       end;
 
 
+    function TInternalAssembler.SetIndirectToSymbol(hp: Tai; const indirectname: string): Boolean;
+      var
+        objsym  : TObjSymbol;
+        indsym  : TObjSymbol;
+      begin
+        Result:=
+          Assigned(hp) and
+          (hp.typ=ait_symbol);
+        if not Result then
+          Exit;
+        objsym:=Objdata.SymbolRef(tai_symbol(hp).sym);
+        objsym.size:=0;
+
+        indsym := TObjSymbol(ObjData.ObjSymbolList.Find(indirectname));
+        if not Assigned(indsym) then
+          begin
+            { it's possible that indirect symbol is not present in the list,
+              so we must create it as undefined }
+            indsym:=TObjSymbol.Create(ObjData.ObjSymbolList, indirectname);
+            indsym.typ:=AT_NONE;
+            indsym.bind:=AB_NONE;
+          end;
+        objsym.indsymbol:=indsym;
+        Result:=true;
+      end;
+
+
     function TInternalAssembler.TreePass0(hp:Tai):Tai;
       var
         objsym,
@@ -989,6 +1019,26 @@ Implementation
                    end;
                  ObjData.alloc(tai_const(hp).size);
                end;
+             ait_directive:
+               begin
+                 case tai_directive(hp).directive of
+                   asd_indirect_symbol:
+                     { handled in TreePass1 }
+                     ;
+                   asd_lazy_reference:
+                     begin
+                       if tai_directive(hp).name = nil then
+                         Internalerror(2009112101);
+                       objsym:=ObjData.symbolref(tai_directive(hp).name^);
+                       objsym.bind:=AB_LAZY;
+                     end;
+                   asd_reference:
+                     { ignore for now, but should be added}
+                     ;
+                   else
+                     internalerror(2010011101);
+                 end;
+               end;
              ait_section:
                begin
                  ObjData.CreateSection(Tai_section(hp).sectype,Tai_section(hp).name^,Tai_section(hp).secorder);
@@ -997,8 +1047,9 @@ Implementation
              ait_symbol :
                begin
                  { needs extra support in the internal assembler }
-                 if tai_symbol(hp).has_value then
-                   internalerror(2009090804);
+                 { the value is just ignored }
+                 {if tai_symbol(hp).has_value then
+                      internalerror(2009090804); ;}
                  ObjData.SymbolDefine(Tai_symbol(hp).sym);
                end;
              ait_label :
@@ -1109,6 +1160,24 @@ Implementation
              ait_cutobject :
                if SmartAsm then
                 break;
+             ait_directive :
+               begin
+                 case tai_directive(hp).directive of
+                   asd_indirect_symbol:
+                     if tai_directive(hp).name = nil then
+                       Internalerror(2009101103)
+                     else if not SetIndirectToSymbol(Tai(hp.Previous), tai_directive(hp).name^) then
+                       Internalerror(2009101102);
+                   asd_lazy_reference:
+                     { handled in TreePass0 }
+                     ;
+                   asd_reference:
+                     { ignore for now, but should be added}
+                     ;
+                   else
+                     internalerror(2010011102);
+                 end;
+               end;
            end;
            hp:=Tai(hp.next);
          end;
@@ -1139,7 +1208,7 @@ Implementation
                    ObjData.writebytes(Tai_align_abstract(hp).calculatefillbuf(fillbuffer,oso_executable in ObjData.CurrObjSec.secoptions)^,
                      Tai_align_abstract(hp).fillsize)
                  else
-                   ObjData.alloc(Tai_align_abstract(hp).fillsize);                   
+                   ObjData.alloc(Tai_align_abstract(hp).fillsize);
                end;
              ait_section :
                begin
@@ -1224,6 +1293,9 @@ Implementation
                          internalerror(200709271);
                        ObjData.writebytes(lebbuf,leblen);
                      end;
+                   aitconst_darwin_dwarf_delta32,
+                   aitconst_darwin_dwarf_delta64:
+                     ObjData.writebytes(Tai_const(hp).value,tai_const(hp).size);
                    else
                      internalerror(200603254);
                  end;

+ 1 - 0
compiler/i386/cputarg.pas

@@ -97,6 +97,7 @@ implementation
 
       ,ogcoff
       ,ogelf
+      ,ogmacho
 
 {**************************************
         Assembler Readers

+ 2103 - 0
compiler/macho.pas

@@ -0,0 +1,2103 @@
+unit macho;
+{
+   * Copyright (c) 1999-2008 Apple Inc.  All Rights Reserved.
+   *
+   * @APPLE_LICENSE_HEADER_START@
+   *
+   * This file contains Original Code and/or Modifications of Original Code
+   * as defined in and that are subject to the Apple Public Source License
+   * Version 2.0 (the 'License'). You may not use this file except in
+   * compliance with the License. Please obtain a copy of the License at
+   * http://www.opensource.apple.com/apsl/ and read it before using this
+   * file.
+   *
+   * The Original Code and all software distributed under the License are
+   * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+   * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+   * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+   * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+   * Please see the License for the specific language governing rights and
+   * limitations under the License.
+   *
+   * @APPLE_LICENSE_HEADER_END@
+    }
+
+{ converted by Dmitry Boyarintsev 2009 }
+
+{$mode objfpc}{$H+}
+
+interface
+
+{$IFDEF FPC}
+{$PACKRECORDS C}
+{$PACKENUM 4}
+{$ENDIF}
+
+
+// mach/$arch/machine.h
+// $arch can be: i386, x86_64, ppc, arm
+// currently used is i386
+
+type
+  integer_t = Integer;
+  uint8_t   = Byte;
+
+  int16_t   = SmallInt;
+  uint16_t  = Word;
+
+  uint32_t  = LongWord;
+  int32_t   = Integer;
+
+  uint64_t  = QWord;
+
+// mach/thread_status.h
+
+{$ifdef i386}  
+
+{$endif i386}
+  
+// mach/machine.h
+
+type
+  cpu_type_t       = integer_t;
+  cpu_subtype_t    = integer_t;
+  cpu_threadtype_t = integer_t;
+
+const
+  CPU_STATE_MAX		= 4;
+
+  CPU_STATE_USER		= 0;
+  CPU_STATE_SYSTEM	= 1;
+  CPU_STATE_IDLE		= 2;
+  CPU_STATE_NICE		= 3;
+
+  {* Capability bits used in the definition of cpu_type. }
+  CPU_ARCH_MASK	  = $ff000000;	{ mask for architecture bits } 
+  CPU_ARCH_ABI64	= $01000000;	{ 64 bit ABI } 
+
+  {	Machine types known by all. }
+
+  CPU_TYPE_ANY		  = -1;
+  CPU_TYPE_VAX		  = 1;
+  CPU_TYPE_MC680x0	= 6;
+  CPU_TYPE_X86		  = 7;
+  CPU_TYPE_I386		  = CPU_TYPE_X86;		{ compatibility }
+  CPU_TYPE_X86_64	  = CPU_TYPE_X86 or CPU_ARCH_ABI64;
+  // skip CPU_TYPE_MIPS		= 8;
+  CPU_TYPE_MC98000	= 10;
+  CPU_TYPE_HPPA     = 11;
+  CPU_TYPE_ARM		  = 12;
+  CPU_TYPE_MC88000	= 13;
+  CPU_TYPE_SPARC		= 14;
+  CPU_TYPE_I860		  = 15;
+  // skip	CPU_TYPE_ALPHA		= 16;	*/
+
+  CPU_TYPE_POWERPC	  = 18;
+  CPU_TYPE_POWERPC64	= CPU_TYPE_POWERPC or CPU_ARCH_ABI64;
+  
+{*
+ *	Machine subtypes (these are defined here, instead of in a machine
+ *	dependent directory, so that any program can get all definitions
+ *	regardless of where is it compiled).
+ *}
+
+{*
+ * Capability bits used in the definition of cpu_subtype.
+ *}
+  CPU_SUBTYPE_MASK 	= $ff000000;	{ mask for feature flags }
+  CPU_SUBTYPE_LIB64	= $80000000;	{ 64 bit libraries }
+
+
+{*
+ *	Object files that are hand-crafted to run on any
+ *	implementation of an architecture are tagged with
+ *	CPU_SUBTYPE_MULTIPLE.  This functions essentially the same as
+ *	the "ALL" subtype of an architecture except that it allows us
+ *	to easily find object files that may need to be modified
+ *	whenever a new implementation of an architecture comes out.
+ *
+ *	It is the responsibility of the implementor to make sure the
+ *	software handles unsupported implementations elegantly.
+ *}
+ 	CPU_SUBTYPE_MULTIPLE		  = -1;
+  CPU_SUBTYPE_LITTLE_ENDIAN	= 0;
+  CPU_SUBTYPE_BIG_ENDIAN		= 1;
+
+{*
+ *     Machine threadtypes.
+ *     This is none - not defined - for most machine types/subtypes.
+ *}
+  CPU_THREADTYPE_NONE	=	0;
+
+{*
+ *	VAX subtypes (these do *not* necessary conform to the actual cpu
+ *	ID assigned by DEC available via the SID register).
+ *}
+
+ 	CPU_SUBTYPE_VAX_ALL	= 0; 
+  CPU_SUBTYPE_VAX780	= 1;
+  CPU_SUBTYPE_VAX785	= 2;
+  CPU_SUBTYPE_VAX750	= 3;
+  CPU_SUBTYPE_VAX730	= 4;
+  CPU_SUBTYPE_UVAXI	  = 5;
+  CPU_SUBTYPE_UVAXII	= 6;
+  CPU_SUBTYPE_VAX8200	= 7;
+  CPU_SUBTYPE_VAX8500	= 8;
+  CPU_SUBTYPE_VAX8600	= 9;
+  CPU_SUBTYPE_VAX8650	= 10;
+  CPU_SUBTYPE_VAX8800	= 11;
+  CPU_SUBTYPE_UVAXIII	= 12;
+
+{*
+ * 	680x0 subtypes
+ *
+ * The subtype definitions here are unusual for historical reasons.
+ * NeXT used to consider 68030 code as generic 68000 code.  For
+ * backwards compatability:
+ * 
+ *	CPU_SUBTYPE_MC68030 symbol has been preserved for source code
+ *	compatability.
+ *
+ *	CPU_SUBTYPE_MC680x0_ALL has been defined to be the same
+ *	subtype as CPU_SUBTYPE_MC68030 for binary comatability.
+ *
+ *	CPU_SUBTYPE_MC68030_ONLY has been added to allow new object
+ *	files to be tagged as containing 68030-specific instructions.
+ *}
+
+ 	CPU_SUBTYPE_MC680x0_ALL  = 1;
+  CPU_SUBTYPE_MC68030		   = 1; { compat }
+  CPU_SUBTYPE_MC68040		   = 2;
+ 	CPU_SUBTYPE_MC68030_ONLY = 3;
+
+  {* I386 subtypes *}
+
+ 	CPU_SUBTYPE_I386_ALL	     =  3 + (0 shl 4);
+  CPU_SUBTYPE_386				     =  3 + (0 shl 4);
+  CPU_SUBTYPE_486				     =  4 + (0 shl 4);
+  CPU_SUBTYPE_486SX			     =  4 + (8 shl 4); // 8 << 4 = 128
+  CPU_SUBTYPE_586				     =  5 + (0 shl 4);
+  CPU_SUBTYPE_PENT	         =  5 + (0 shl 4);
+  CPU_SUBTYPE_PENTPRO	       =  6 + (1 shl 4);
+  CPU_SUBTYPE_PENTII_M3	     =  6 + (3 shl 4);
+  CPU_SUBTYPE_PENTII_M5	     =  6 + (5 shl 4);
+  CPU_SUBTYPE_CELERON				 =  7 + (6 shl 4);
+  CPU_SUBTYPE_CELERON_MOBILE =  7 + (7 shl 4);
+  CPU_SUBTYPE_PENTIUM_3			 =  8 + (0 shl 4);
+  CPU_SUBTYPE_PENTIUM_3_M		 =  8 + (1 shl 4);
+  CPU_SUBTYPE_PENTIUM_3_XEON =  8 + (2 shl 4);
+  CPU_SUBTYPE_PENTIUM_M			 =  9 + (0 shl 4);
+  CPU_SUBTYPE_PENTIUM_4			 = 10 + (0 shl 4);
+  CPU_SUBTYPE_PENTIUM_4_M		 = 10 + (1 shl 4);
+  CPU_SUBTYPE_ITANIUM				 = 11 + (0 shl 4);
+  CPU_SUBTYPE_ITANIUM_2		   = 11 + (1 shl 4);
+  CPU_SUBTYPE_XEON				   = 12 + (0 shl 4);
+  CPU_SUBTYPE_XEON_MP			   = 12 + (1 shl 4);
+                                  
+  CPU_SUBTYPE_INTEL_FAMILY_MAX	=  15;
+  CPU_SUBTYPE_INTEL_MODEL_ALL	= 0;
+
+  {* X86 subtypes. *}
+ 
+  CPU_SUBTYPE_X86_ALL		 = 3;
+  CPU_SUBTYPE_X86_64_ALL = 3;
+  CPU_SUBTYPE_X86_ARCH1	 = 4;
+
+
+  CPU_THREADTYPE_INTEL_HTT = 1;
+
+  {*	Mips subtypes. *}
+
+ 	CPU_SUBTYPE_MIPS_ALL	  = 0;
+  CPU_SUBTYPE_MIPS_R2300	= 1;
+  CPU_SUBTYPE_MIPS_R2600	= 2;
+  CPU_SUBTYPE_MIPS_R2800	= 3;
+  CPU_SUBTYPE_MIPS_R2000a	= 4;	{* pmax *}
+  CPU_SUBTYPE_MIPS_R2000	= 5;
+  CPU_SUBTYPE_MIPS_R3000a	= 6;	{ 3max *}
+  CPU_SUBTYPE_MIPS_R3000	= 7;
+
+  {* MC98000 (PowerPC) subtypes *}
+ 	CPU_SUBTYPE_MC98000_ALL	= 0;
+  CPU_SUBTYPE_MC98601	    = 1;
+
+{*
+ *	HPPA subtypes for Hewlett-Packard HP-PA family of
+ *	risc processors. Port by NeXT to 700 series. 
+ *}
+
+ 	CPU_SUBTYPE_HPPA_ALL		= 0;
+  CPU_SUBTYPE_HPPA_7100		= 0; {* compat *}
+  CPU_SUBTYPE_HPPA_7100LC	= 1;
+
+  {* MC88000 subtypes. *}
+  
+ 	CPU_SUBTYPE_MC88000_ALL	= 0;
+  CPU_SUBTYPE_MC88100	    = 1;
+  CPU_SUBTYPE_MC88110	    = 2;
+
+  {* SPARC subtypes  *}
+ 	CPU_SUBTYPE_SPARC_ALL		= 0;
+
+  {* I860 subtypes *}
+  CPU_SUBTYPE_I860_ALL	=  0;
+  CPU_SUBTYPE_I860_860	=  1;
+
+  {* PowerPC subtypes *}
+  
+  CPU_SUBTYPE_POWERPC_ALL		= 0;
+  CPU_SUBTYPE_POWERPC_601		= 1;
+  CPU_SUBTYPE_POWERPC_602		= 2;
+  CPU_SUBTYPE_POWERPC_603		= 3;
+  CPU_SUBTYPE_POWERPC_603e	= 4;
+  CPU_SUBTYPE_POWERPC_603ev	= 5;
+  CPU_SUBTYPE_POWERPC_604		= 6;
+  CPU_SUBTYPE_POWERPC_604e	= 7;
+  CPU_SUBTYPE_POWERPC_620		= 8;
+  CPU_SUBTYPE_POWERPC_750		= 9;
+  CPU_SUBTYPE_POWERPC_7400	= 10;
+  CPU_SUBTYPE_POWERPC_7450	= 11;
+  CPU_SUBTYPE_POWERPC_970		= 100;
+
+  {* ARM subtypes *}
+  CPU_SUBTYPE_ARM_ALL       = 0;
+  CPU_SUBTYPE_ARM_V4T       = 5;
+  CPU_SUBTYPE_ARM_V6        = 6;
+  CPU_SUBTYPE_ARM_V5TEJ     = 7;
+  CPU_SUBTYPE_ARM_XSCALE		= 8;
+
+{*
+ *	CPU families (sysctl hw.cpufamily)
+ *
+ * These are meant to identify the CPU's marketing name - an
+ * application can map these to (possibly) localized strings.
+ * NB: the encodings of the CPU families are intentionally arbitrary.
+ * There is no ordering, and you should never try to deduce whether
+ * or not some feature is available based on the family.
+ * Use feature flags (eg, hw.optional.altivec) to test for optional
+ * functionality.
+ *}
+  CPUFAMILY_UNKNOWN    = 0;
+  CPUFAMILY_POWERPC_G3 = $cee41549;
+  CPUFAMILY_POWERPC_G4 = $77c184ae;
+  CPUFAMILY_POWERPC_G5 = $ed76d8aa;
+  CPUFAMILY_INTEL_6_13 = $aa33392b;
+  CPUFAMILY_INTEL_6_14 = $73d67300;  { "Intel Core Solo" and "Intel Core Duo" (32-bit Pentium-M with SSE3) }
+  CPUFAMILY_INTEL_6_15 = $426f69ef;  { "Intel Core 2 Duo" }
+  CPUFAMILY_INTEL_6_23 = $78ea4fbc;  { Penryn }
+  CPUFAMILY_INTEL_6_26 = $6b5a4cd2;  { Nehalem }
+  CPUFAMILY_ARM_9      = $e73283ae;
+  CPUFAMILY_ARM_11     = $8ff620d8;
+  CPUFAMILY_ARM_XSCALE = $53b005f5;
+  
+  CPUFAMILY_INTEL_YONAH	  = CPUFAMILY_INTEL_6_14;
+  CPUFAMILY_INTEL_MEROM	  = CPUFAMILY_INTEL_6_15;
+  CPUFAMILY_INTEL_PENRYN	= CPUFAMILY_INTEL_6_23;
+  CPUFAMILY_INTEL_NEHALEM	= CPUFAMILY_INTEL_6_26;
+  
+  CPUFAMILY_INTEL_CORE	 = CPUFAMILY_INTEL_6_14;
+  CPUFAMILY_INTEL_CORE2	 = CPUFAMILY_INTEL_6_15;
+  
+// mach/vm_prot.h
+type
+  vm_prot_t = Integer;
+
+const
+  VM_PROT_NONE	 = $00;
+
+  VM_PROT_READ	 = $01;	{* read permission *}
+  VM_PROT_WRITE	 = $02;	{* write permission *}
+  VM_PROT_EXECUTE	= $04;	{* execute permission *}
+
+{*
+ *	The default protection for newly-created virtual memory
+ *}
+
+  VM_PROT_DEFAULT	= VM_PROT_READ or VM_PROT_WRITE;
+
+{*
+ *	The maximum privileges possible, for parameter checking.
+ *}
+
+  VM_PROT_ALL	 = VM_PROT_READ or VM_PROT_WRITE or VM_PROT_EXECUTE;
+
+{*
+ *	An invalid protection value.
+ *	Used only by memory_object_lock_request to indicate no change
+ *	to page locks.  Using -1 here is a bad idea because it
+ *	looks like VM_PROT_ALL and then some.
+ *}
+
+  VM_PROT_NO_CHANGE	= $08;
+
+{*
+ *      When a caller finds that he cannot obtain write permission on a
+ *      mapped entry, the following flag can be used.  The entry will
+ *      be made "needs copy" effectively copying the object (using COW),
+ *      and write permission will be added to the maximum protections
+ *      for the associated entry.
+ *}
+
+  VM_PROT_COPY = $10;
+
+
+{*
+ *	Another invalid protection value.
+ *	Used only by memory_object_data_request upon an object
+ *	which has specified a copy_call copy strategy. It is used
+ *	when the kernel wants a page belonging to a copy of the
+ *	object, and is only asking the object as a result of
+ *	following a shadow chain. This solves the race between pages
+ *	being pushed up by the memory manager and the kernel
+ *	walking down the shadow chain.
+ *}
+
+  VM_PROT_WANTS_COPY = $10;
+
+  
+{ Constant for the magic field of the mach_header (32-bit architectures)  the mach magic number  }
+
+const
+  MH_MAGIC = $feedface;
+  MH_CIGAM = $cefaedfe; { NXSwapInt(MH_MAGIC)  }
+
+
+type
+  { * The 32-bit mach header appears at the very beginning of the object file for 32-bit architectures. }
+  mach_header = record
+    magic       : uint32_t;      { mach magic number identifier  }
+    cputype     : cpu_type_t;    { cpu specifier  }
+    cpusubtype  : cpu_subtype_t; { machine specifier  }
+    filetype    : uint32_t;      { type of file  }
+    ncmds       : uint32_t;      { number of load commands  }
+    sizeofcmds  : uint32_t;      { the size of all the load commands  }
+    flags       : uint32_t;      { flags  }
+  end;
+  pmach_header = ^mach_header;
+
+type
+  {* The 64-bit mach header appears at the very beginning of object files for
+   * 64-bit architectures. }
+  mach_header_64 = record
+    magic      : uint32_t;      { mach magic number identifier  }
+    cputype    : cpu_type_t;    { cpu specifier  }
+    cpusubtype : cpu_subtype_t; { machine specifier  }
+    filetype   : uint32_t;      { type of file  }
+    ncmds      : uint32_t;      { number of load commands  }
+    sizeofcmds : uint32_t;      { the size of all the load commands  }
+    flags      : uint32_t;      { flags  }
+    reserved   : uint32_t;      { reserved  }
+  end;
+  pmach_header_64 = ^mach_header_64;
+
+  { Constant for the magic field of the mach_header_64 (64-bit architectures)  }
+  { the 64-bit mach magic number  }
+
+const
+   MH_MAGIC_64 = $feedfacf;
+   MH_CIGAM_64 = $cffaedfe; { NXSwapInt(MH_MAGIC_64)  }
+
+  {* The layout of the file depends on the filetype.  For all but the MH_OBJECT
+   * file type the segments are padded out and aligned on a segment alignment
+   * boundary for efficient demand pageing.  The MH_EXECUTE, MH_FVMLIB, MH_DYLIB,
+   * MH_DYLINKER and MH_BUNDLE file types also have the headers included as part
+   * of their first segment.
+   *
+   * The file type MH_OBJECT is a compact format intended as output of the
+   * assembler and input (and possibly output) of the link editor (the .o
+   * format).  All sections are in one unnamed segment with no segment padding.
+   * This format is used as an executable format when the file is so small the
+   * segment padding greatly increases its size.
+   *
+   * The file type MH_PRELOAD is an executable format intended for things that
+   * are not executed under the kernel (proms, stand alones, kernels, etc).  The
+   * format can be executed under the kernel but may demand paged it and not
+   * preload it before execution.
+   *
+   * A core file is in MH_CORE format and can be any in an arbritray legal
+   * Mach-O file.
+   *
+   * Constants for the filetype field of the mach_header }
+const
+  MH_OBJECT     = $1; { relocatable object file  }
+  MH_EXECUTE    = $2; { demand paged executable file  }
+  MH_FVMLIB     = $3; { fixed VM shared library file  }
+  MH_CORE       = $4; { core file  }
+  MH_PRELOAD    = $5; { preloaded executable file  }
+  MH_DYLIB      = $6; { dynamically bound shared library  }
+  MH_DYLINKER   = $7; { dynamic link editor  }
+  MH_BUNDLE     = $8; { dynamically bound bundle file  }
+  MH_DYLIB_STUB = $9; { shared library stub for static  }
+  MH_DSYM       = $a; { linking only, no section contents   }
+                      { companion file with only debug sections  }
+
+const
+  { Constants for the flags field of the mach_header  }
+  
+  MH_NOUNDEFS     = $1;   { the object file has no undefined references  }
+  MH_INCRLINK     = $2;   { the object file is the output of an  incremental link against a base file and can't be link edited again  }
+  MH_DYLDLINK     = $4;   { the object file is input for the dynamic linker and can't be staticly link edited again  }
+  MH_BINDATLOAD   = $8;   { the object file's undefined references are bound by the dynamic linker when loaded.  }
+  MH_PREBOUND     = $10;  { the file has its dynamic undefined references prebound.  }
+  MH_SPLIT_SEGS   = $20;  { the file has its read-only and read-write segments split  }
+  MH_LAZY_INIT    = $40;  { the shared library init routine is to be run lazily via catching memory faults to its writeable segments (obsolete)  }
+  MH_TWOLEVEL     = $80;  { the image is using two-level name space bindings  }
+  MH_FORCE_FLAT   = $100; { the executable is forcing all images to use flat name space bindings  }
+  MH_NOMULTIDEFS  = $200; { this umbrella guarantees no multiple defintions of symbols in its sub-images so the two-level namespace hints can always be used.  }
+  MH_NOFIXPREBINDING = $400;  { do not have dyld notify the prebinding agent about this executable  }
+  MH_PREBINDABLE     = $800;  { the binary is not prebound but can have its prebinding redone. only used when MH_PREBOUND is not set.  }
+  MH_ALLMODSBOUND    = $1000; { indicates that this binary binds to  all two-level namespace modules of                }
+                 			    		{ its dependent libraries. only used  when MH_PREBINDABLE and MH_TWOLEVEL are both set.  }
+  MH_SUBSECTIONS_VIA_SYMBOLS = $2000; { safe to divide up the sections into sub-sections via symbols for dead code stripping  }
+  MH_CANONICAL      = $4000;  { the binary has been canonicalized via the unprebind operation  }
+  MH_WEAK_DEFINES   = $8000;  { the final linked image contains external weak symbols  }
+  MH_BINDS_TO_WEAK  = $10000; { the final linked image uses weak symbols  }
+  MH_ALLOW_STACK_EXECUTION = $20000; { When this bit is set, all stacks in the task will be given stack }
+                                     {	execution privilege.  Only used in MH_EXECUTE filetypes.        }
+  MH_ROOT_SAFE = $40000; { When this bit is set, the binary declares it is safe for use in processes with uid zero  }
+  MH_SETUID_SAFE = $80000; { When this bit is set, the binary declares it is safe for use in processes when issetugid() is true  }
+  MH_NO_REEXPORTED_DYLIBS = $100000; { When this bit is set on a dylib, the static linker does not need to examine dependent dylibs to see if any are re-exported  }
+  MH_PIE = $200000; { When this bit is set, the OS will load the main executable at a random address.  Only used in MH_EXECUTE filetypes.  }
+
+  {
+   * The load commands directly follow the mach_header.  The total size of all
+   * of the commands is given by the sizeofcmds field in the mach_header.  All
+   * load commands must have as their first two fields cmd and cmdsize.  The cmd
+   * field is filled in with a constant for that command type.  Each command type
+   * has a structure specifically for it.  The cmdsize field is the size in bytes
+   * of the particular load command structure plus anything that follows it that
+   * is a part of the load command (i.e. section structures, strings, etc.).  To
+   * advance to the next load command the cmdsize can be added to the offset or
+   * pointer of the current load command.  The cmdsize for 32-bit architectures
+   * MUST be a multiple of 4 bytes and for 64-bit architectures MUST be a multiple
+   * of 8 bytes (these are forever the maximum alignment of any load commands).
+   * The padded bytes must be zero.  All tables in the object file must also
+   * follow these rules so the file can be memory mapped.  Otherwise the pointers
+   * to these tables will not work well or at all on some machines.  With all
+   * padding zeroed like objects will compare byte for byte.
+    }
+
+type
+  load_command = record
+    cmd     : uint32_t; { type of load command  }
+    cmdsize : uint32_t; { total size of command in bytes  }
+  end;
+  pload_command = ^load_command;
+
+  {
+   * After MacOS X 10.1 when a new load command is added that is required to be
+   * understood by the dynamic linker for the image to execute properly the
+   * LC_REQ_DYLD bit will be or'ed into the load command constant.  If the dynamic
+   * linker sees such a load command it it does not understand will issue a
+   * "unknown load command required for execution" error and refuse to use the
+   * image.  Other load commands without this bit that are not understood will
+   * simply be ignored.
+    }
+
+{ Constants for the cmd field of all load commands, the type  }
+
+const
+  LC_REQ_DYLD   = $80000000; { segment of this file to be mapped  }
+  LC_SEGMENT    = $1; { link-edit stab symbol table info  }
+  LC_SYMTAB     = $2;  { link-edit gdb symbol table info (obsolete)  }
+  LC_SYMSEG     = $3;  { thread  }
+  LC_THREAD     = $4;  { unix thread (includes a stack)  }
+  LC_UNIXTHREAD = $5;  { load a specified fixed VM shared library  }
+  LC_LOADFVMLIB = $6;  { fixed VM shared library identification  }
+  LC_IDFVMLIB   = $7;    { object identification info (obsolete)  }
+  LC_IDENT      = $8;     { fixed VM file inclusion (internal use)  }
+  LC_FVMFILE    = $9;  { prepage command (internal use)  }
+  LC_PREPAGE    = $a;  { dynamic link-edit symbol table info  }
+  LC_DYSYMTAB   = $b; { load a dynamically linked shared library  }
+  LC_LOAD_DYLIB = $c; { dynamically linked shared lib ident  }
+  LC_ID_DYLIB   = $d; { load a dynamic linker  }
+  LC_LOAD_DYLINKER  = $e; { dynamic linker identification  }
+  LC_ID_DYLINKER    = $f; { modules prebound for a dynamically  }
+  LC_PREBOUND_DYLIB = $10;  {  linked shared library  }
+  LC_ROUTINES       = $11; { image routines  }
+  LC_SUB_FRAMEWORK  = $12; { sub framework  }
+  LC_SUB_UMBRELLA   = $13; { sub umbrella  }
+  LC_SUB_CLIENT     = $14; { sub client  }
+  LC_SUB_LIBRARY    = $15; { sub library  }
+  LC_TWOLEVEL_HINTS = $16; { two-level namespace lookup hints  }
+  LC_PREBIND_CKSUM  = $17; { prebind checksum  }
+  LC_LOAD_WEAK_DYLIB = $18 or LC_REQ_DYLD; { load a dynamically linked shared library that is allowed to be missing  (all symbols are weak imported). }
+  LC_SEGMENT_64   = $19; { 64-bit segment of this file to be mapped  }
+  LC_ROUTINES_64  = $1a; { 64-bit image routines  }
+  LC_UUID         = $1b; { the uuid  }
+  LC_RPATH        = $1c or LC_REQ_DYLD; { runpath additions  }
+  LC_CODE_SIGNATURE     = $1d; { local of code signature  }
+  LC_SEGMENT_SPLIT_INFO = $1e; { local of info to split segments  }
+  LC_REEXPORT_DYLIB     = $1f or LC_REQ_DYLD; { load and re-export dylib  }
+  LC_LAZY_LOAD_DYLIB    = $20; { delay load of dylib until first use  }
+  LC_ENCRYPTION_INFO    = $21; { encrypted segment information  }
+  {
+   * A variable length string in a load command is represented by an lc_str
+   * union.  The strings are stored just after the load command structure and
+   * the offset is from the start of the load command structure.  The size
+   * of the string is reflected in the cmdsize field of the load command.
+   * Once again any padded bytes to bring the cmdsize field to a multiple
+   * of 4 bytes must be zero.
+    }
+  { offset to the string  }
+{$ifndef __LP64__}
+  { pointer to the string  }
+{$endif}
+
+type
+  lc_str = record
+  case longint of
+    0 : ( offset : uint32_t );
+    1 : ( ptr : ^char );
+  end;
+
+  {
+   * The segment load command indicates that a part of this file is to be
+   * mapped into the task's address space.  The size of this segment in memory,
+   * vmsize, maybe equal to or larger than the amount to map from this file,
+   * filesize.  The file is mapped starting at fileoff to the beginning of
+   * the segment in memory, vmaddr.  The rest of the memory of the segment,
+   * if any, is allocated zero fill on demand.  The segment's maximum virtual
+   * memory protection and initial virtual memory protection are specified
+   * by the maxprot and initprot fields.  If the segment has sections then the
+   * section structures directly follow the segment command and their size is
+   * reflected in cmdsize.
+    }
+  
+  { for 32-bit architectures  }            
+  
+  segment_command = record           
+    cmd      : uint32_t;             { LC_SEGMENT  }                          
+    cmdsize  : uint32_t;             { includes sizeof section structs  }     
+    segname  : array[0..15] of char; { segment name  }                        
+    vmaddr   : uint32_t;             { memory address of this segment  }      
+    vmsize   : uint32_t;             { memory size of this segment  }         
+    fileoff  : uint32_t;             { file offset of this segment  }         
+    filesize : uint32_t;             { amount to map from the file  }         
+    maxprot  : vm_prot_t;            { maximum VM protection  }               
+    initprot : vm_prot_t;            { initial VM protection  }               
+    nsects   : uint32_t;             { number of sections in segment  }       
+    flags    : uint32_t;             { flags  }                               
+  end;
+  psegment_command = ^segment_command;
+
+  {
+   * The 64-bit segment load command indicates that a part of this file is to be
+   * mapped into a 64-bit task's address space.  If the 64-bit segment has
+   * sections then section_64 structures directly follow the 64-bit segment
+   * command and their size is reflected in cmdsize.
+    }
+  { for 64-bit architectures  }
+  
+  segment_command_64 = record
+    cmd      : uint32_t;              { LC_SEGMENT_64  }                      
+    cmdsize  : uint32_t;              { includes sizeof section_64 structs  }
+    segname  : array[0..15] of char;  { segment name  }                      
+    vmaddr   : uint64_t;              { memory address of this segment  }    
+    vmsize   : uint64_t;              { memory size of this segment  }       
+    fileoff  : uint64_t;              { file offset of this segment  }       
+    filesize : uint64_t;              { amount to map from the file  }       
+    maxprot  : vm_prot_t;             { maximum VM protection  }             
+    initprot : vm_prot_t;             { initial VM protection  }             
+    nsects   : uint32_t;              { number of sections in segment  }     
+    flags    : uint32_t;              { flags  }                             
+  end;
+  psegment_command_64 = ^segment_command_64;
+
+  { Constants for the flags field of the segment_command  }
+
+const
+   SG_HIGHVM = $1; { the file contents for this segment is for   }
+                   { the high part of the VM space, the low part }
+                   { is zero filled (for stacks in core files)   }
+
+  SG_FVMLIB = $2;  { this segment is the VM that is allocated by }
+                   {	a fixed VM library, for overlap checking in }
+                   { the link editor  }                           
+   
+  SG_NORELOC = $4; { this segment has nothing that was relocated }
+                   { in it and nothing relocated to it, that is  }
+                   { it maybe safely replaced without relocation }
+     
+  SG_PROTECTED_VERSION_1 = $8;  { This segment is protected.  If the    }
+                                {	segment starts at file offset 0, the  }
+                                {	first page of the segment is not      }
+                                {	protected.  All other pages of the    }
+                                {	segment are protected.                }
+     
+  {* A segment is made up of zero or more sections.  Non-MH_OBJECT files have
+   * all of their segments with the proper sections in each, and padded to the
+   * specified segment alignment when produced by the link editor.  The first
+   * segment of a MH_EXECUTE and MH_FVMLIB format file contains the mach_header
+   * and load commands of the object file before its first section.  The zero
+   * fill sections are always last in their segment (in all formats).  This
+   * allows the zeroed segment padding to be mapped into memory where zero fill
+   * sections might be. The gigabyte zero fill sections, those with the section
+   * type S_GB_ZEROFILL, can only be in a segment with sections of this type.
+   * These segments are then placed after all other segments.
+   *
+   * The MH_OBJECT format has all of its sections in one segment for
+   * compactness.  There is no padding to a specified segment boundary and the
+   * mach_header and load commands are not part of the segment.
+   *
+   * Sections with the same section name, sectname, going into the same segment,
+   * segname, are combined by the link editor.  The resulting section is aligned
+   * to the maximum alignment of the combined sections and is the new section's
+   * alignment.  The combined sections are aligned to their original alignment in
+   * the combined section.  Any padded bytes to get the specified alignment are
+   * zeroed.
+   *
+   * The format of the relocation entries referenced by the reloff and nreloc
+   * fields of the section structure for mach object files is described in the
+   * header file <reloc.h>.  }
+
+type
+  { for 32-bit architectures  }
+  section = record
+    sectname  : array[0..15] of char; { name of this section  }
+    segname   : array[0..15] of char; { segment this section goes in  }
+    addr      : uint32_t;             { memory address of this section  }
+    size      : uint32_t;             { size in bytes of this section  }
+    offset    : uint32_t;             { file offset of this section  }
+    align     : uint32_t;             { section alignment (power of 2)  }
+    reloff    : uint32_t;             { file offset of relocation entries  }
+    nreloc    : uint32_t;             { number of relocation entries  }
+    flags     : uint32_t;             { flags (section type and attributes) }
+    reserved1 : uint32_t;             { reserved (for offset or index)  }
+    reserved2 : uint32_t;             { reserved (for count or sizeof)  }
+  end;
+  psection = ^section;
+
+
+  { for 64-bit architectures  }
+  section_64 = record
+    sectname  : array[0..15] of char; { name of this section  }
+    segname   : array[0..15] of char; { segment this section goes in  }
+    addr      : uint64_t;             { memory address of this section  }
+    size      : uint64_t;             { size in bytes of this section  }
+    offset    : uint32_t;             { file offset of this section  }
+    align     : uint32_t;             { section alignment (power of 2)  }
+    reloff    : uint32_t;             { file offset of relocation entries  }
+    nreloc    : uint32_t;             { number of relocation entries  }
+    flags     : uint32_t;             { flags (section type and attributes) }
+    reserved1 : uint32_t;             { reserved (for offset or index)  }
+    reserved2 : uint32_t;             { reserved (for count or sizeof)  }
+    reserved3 : uint32_t;             { reserved  }
+  end;
+  psection_64 = ^section_64;
+
+  {* The flags field of a section structure is separated into two parts a section
+   * type and section attributes.  The section types are mutually exclusive (it
+   * can only have one type) but the section attributes are not (it may have more
+   * than one attribute). }
+
+  { 256 section types  }
+
+const
+  SECTION_TYPE       = $000000ff; { Constants for the type of a section  }
+  SECTION_ATTRIBUTES = $ffffff00; {  24 section attributes  }
+  S_REGULAR          = $0;        { regular section  }
+  S_ZEROFILL         = $1;        { zero fill on demand section  }
+  S_CSTRING_LITERALS = $2;        { section with only literal C strings }
+  S_4BYTE_LITERALS   = $3;        { section with only 4 byte literals  }
+  S_8BYTE_LITERALS   = $4;        { section with only 8 byte literals  }
+  S_LITERAL_POINTERS = $5;        { section with only pointers to literals  }
+
+  {* For the two types of symbol pointers sections and the symbol stubs section
+   * they have indirect symbol table entries.  For each of the entries in the
+   * section the indirect symbol table entries, in corresponding order in the
+   * indirect symbol table, start at the index stored in the reserved1 field
+   * of the section structure.  Since the indirect symbol table entries
+   * correspond to the entries in the section the number of indirect symbol table
+   * entries is inferred from the size of the section divided by the size of the
+   * entries in the section.  For symbol pointers sections the size of the entries
+   * in the section is 4 bytes and for symbol stubs sections the byte size of the
+   * stubs is stored in the reserved2 field of the section structure.  }
+
+  S_NON_LAZY_SYMBOL_POINTERS = $6;    { section with only non-lazy symbol pointers  }
+  S_LAZY_SYMBOL_POINTERS     = $7;    { section with only lazy symbol pointers  }
+  S_SYMBOL_STUBS             = $8;    { section with only symbol stubs, byte size of stub in the reserved2 field  }
+  S_MOD_INIT_FUNC_POINTERS   = $9;    { section with only function pointers for initialization }
+  S_MOD_TERM_FUNC_POINTERS   = $a;    { section with only function pointers for termination  }
+  S_COALESCED                = $b;    { section contains symbols that are to be coalesced  }
+  S_GB_ZEROFILL              = $c;    { zero fill on demand section (that can be larger than 4 gigabytes)  }
+  S_INTERPOSING              = $d;    { section with only pairs of function pointers for interposing  }
+  S_16BYTE_LITERALS          = $e;    { section with only 16 byte	literals  }
+  S_DTRACE_DOF               = $f;    { section contains DTrace Object Format  }
+  S_LAZY_DYLIB_SYMBOL_POINTERS = $10; { section with only lazy symbol pointers to lazy loaded dylibs  }
+
+  {* Constants for the section attributes part of the flags field of a section structure.  }
+  
+  SECTION_ATTRIBUTES_USR     = $ff000000; { User setable attributes  }
+  
+  S_ATTR_PURE_INSTRUCTIONS   = $80000000; { section contains only true machine instructions  }
+  S_ATTR_NO_TOC              = $40000000; { section contains coalesced symbols }
+                                          { that are not to be in a ranlib table of contents  }
+  S_ATTR_STRIP_STATIC_SYMS   = $20000000; { ok to strip static symbols this section }
+                                          { in files with the MH_DYLDLINK flag  }
+  S_ATTR_NO_DEAD_STRIP       = $10000000; { no dead stripping  }
+  S_ATTR_LIVE_SUPPORT        = $08000000; { blocks are live if they reference live blocks  }
+  S_ATTR_SELF_MODIFYING_CODE = $04000000; { Used with i386 code stubs written on by dyld  }
+  
+  {
+   * If a segment contains any sections marked with S_ATTR_DEBUG then all
+   * sections in that segment must have this attribute.  No section other than
+   * a section marked with this attribute may reference the contents of this
+   * section.  A section with this attribute may contain no symbols and must have
+   * a section type S_REGULAR.  The static linker will not copy section contents
+   * from sections with this attribute into its output file.  These sections
+   * generally contain DWARF debugging info.
+    }  { a debug section  }
+     S_ATTR_DEBUG = $02000000;
+  { system setable attributes  }
+     SECTION_ATTRIBUTES_SYS = $00ffff00;
+  { section contains some
+  						   machine instructions  }
+     S_ATTR_SOME_INSTRUCTIONS = $00000400;
+  { section has external
+  						   relocation entries  }
+     S_ATTR_EXT_RELOC = $00000200;
+  { section has local
+  						   relocation entries  }
+     S_ATTR_LOC_RELOC = $00000100;
+  {
+   * The names of segments and sections in them are mostly meaningless to the
+   * link-editor.  But there are few things to support traditional UNIX
+   * executables that require the link-editor and assembler to use some names
+   * agreed upon by convention.
+   *
+   * The initial protection of the "__TEXT" segment has write protection turned
+   * off (not writeable).
+   *
+   * The link-editor will allocate common symbols at the end of the "__common"
+   * section in the "__DATA" segment.  It will create the section and segment
+   * if needed.
+    }
+  { The currently known segment names and the section names in those segments  }
+
+
+  SEG_PAGEZERO = '__PAGEZERO'; { the pagezero segment which has no  }
+                               { protections and catches NULL references for MH_EXECUTE files  }
+
+  SEG_TEXT  = '__TEXT';                 { the tradition UNIX text segment  }
+  SECT_TEXT         = '__text';         { the real text part of the text  }
+  SECT_FVMLIB_INIT0 = '__fvmlib_init0'; { the fvmlib initialization   section  }
+  SECT_FVMLIB_INIT1 = '__fvmlib_init1'; { the section following the fvmlib initialization  section  }
+
+  SEG_DATA = '__DATA';       { the tradition UNIX data segment  }
+  SECT_DATA   = '__data';   { the real initialized data section no padding, no bss overlap  }
+  SECT_BSS    = '__bss';    { the real uninitialized data section no padding  }
+  SECT_COMMON = '__common'; { the section common symbols are allocated in by the link editor  }
+
+  SEG_OBJC = '__OBJC';                   { objective-C runtime segment  }
+  SECT_OBJC_SYMBOLS = '__symbol_table';  { symbol table  }
+  SECT_OBJC_MODULES = '__module_info';   { module information  }
+  SECT_OBJC_STRINGS = '__selector_strs'; { string table  }
+  SECT_OBJC_REFS    = '__selector_refs'; { string table  }
+
+  SEG_ICON = '__ICON';            { the icon segment  }
+  SECT_ICON_HEADER = '__header';  { the icon headers  }
+  SECT_ICON_TIFF   = '__tiff';    { the icons in tiff format  }
+
+  SEG_LINKEDIT = '__LINKEDIT'; { the segment containing all structs  }
+                               { created and maintained by the linkeditor. }
+                               { Created with -seglinkedit  option to ld(1) for MH_EXECUTE and FVMLIB file types only  }
+
+  SEG_UNIXSTACK = '__UNIXSTACK'; { the unix stack segment  }
+
+  SEG_IMPORT = '__IMPORT'; { the segment for the self (dyld)  }
+                           { modifing code stubs that has read, write and execute permissions  }
+
+  {* Fixed virtual memory shared libraries are identified by two things.  The
+   * target pathname (the name of the library as found for execution), and the
+   * minor version number.  The address of where the headers are loaded is in
+   * header_addr. (THIS IS OBSOLETE and no longer supported). }
+
+type
+  fvmlib = record
+    name          : lc_str;   { library's target pathname  }
+    minor_version : uint32_t; { library's minor version number  }
+    header_addr   : uint32_t; { library's header address  }
+  end;
+
+  {* A fixed virtual shared library (filetype == MH_FVMLIB in the mach header)
+   * contains a fvmlib_command (cmd == LC_IDFVMLIB) to identify the library.
+   * An object that uses a fixed virtual shared library also contains a
+   * fvmlib_command (cmd == LC_LOADFVMLIB) for each library it uses.
+   * (THIS IS OBSOLETE and no longer supported). }
+
+  fvmlib_command = record
+    cmd     : uint32_t; { LC_IDFVMLIB or LC_LOADFVMLIB  }
+    cmdsize : uint32_t; { includes pathname string  }
+    fvmlib  : fvmlib;   { the library identification  }
+  end;
+  pfvmlib_command = ^fvmlib_command;
+
+  {* Dynamicly linked shared libraries are identified by two things.  The
+   * pathname (the name of the library as found for execution), and the
+   * compatibility version number.  The pathname must match and the compatibility
+   * number in the user of the library must be greater than or equal to the
+   * library being used.  The time stamp is used to record the time a library was
+   * built and copied into user so it can be use to determined if the library used
+   * at runtime is exactly the same as used to built the program.  }
+
+  dylib = record
+    name                  : lc_str;   { library's path name  }
+    timestamp             : uint32_t; { library's build time stamp  }
+    current_version       : uint32_t; { library's current version number  }
+    compatibility_version : uint32_t; { library's compatibility vers number }
+  end;
+
+  {* A dynamically linked shared library (filetype == MH_DYLIB in the mach header)
+   * contains a dylib_command (cmd == LC_ID_DYLIB) to identify the library.
+   * An object that uses a dynamically linked shared library also contains a
+   * dylib_command (cmd == LC_LOAD_DYLIB, LC_LOAD_WEAK_DYLIB, or
+   * LC_REEXPORT_DYLIB) for each library it uses. }
+
+  dylib_command = record
+    cmd     : uint32_t; { LC_ID_DYLIB, LC_LOAD_DYLIB,WEAK_DYLIB, LC_REEXPORT_DYLIB  }
+    cmdsize : uint32_t; { includes pathname string  }
+    dylib   : dylib;    { the library identification  }
+  end;
+  pdylib_command = ^dylib_command;
+
+  {* A dynamically linked shared library may be a subframework of an umbrella
+   * framework.  If so it will be linked with "-umbrella umbrella_name" where
+   * Where "umbrella_name" is the name of the umbrella framework. A subframework
+   * can only be linked against by its umbrella framework or other subframeworks
+   * that are part of the same umbrella framework.  Otherwise the static link
+   * editor produces an error and states to link against the umbrella framework.
+   * The name of the umbrella framework for subframeworks is recorded in the
+   * following structure. }
+
+  sub_framework_command = record
+    cmd       : uint32_t; { LC_SUB_FRAMEWORK  }
+    cmdsize   : uint32_t; { includes umbrella string  }
+    umbrella  : lc_str;   { the umbrella framework name  }
+  end;
+  psub_framework_command = ^sub_framework_command;
+
+
+  {* For dynamically linked shared libraries that are subframework of an umbrella
+   * framework they can allow clients other than the umbrella framework or other
+   * subframeworks in the same umbrella framework.  To do this the subframework
+   * is built with "-allowable_client client_name" and an LC_SUB_CLIENT load
+   * command is created for each -allowable_client flag.  The client_name is
+   * usually a framework name.  It can also be a name used for bundles clients
+   * where the bundle is built with "-client_name client_name". }
+
+  sub_client_command = record
+    cmd     : uint32_t; { LC_SUB_CLIENT  }
+    cmdsize : uint32_t; { includes client string  }
+    client  : lc_str;   { the client name  }
+  end;
+  psub_client_command = ^sub_client_command;
+
+  {
+   * A dynamically linked shared library may be a sub_umbrella of an umbrella
+   * framework.  If so it will be linked with "-sub_umbrella umbrella_name" where
+   * Where "umbrella_name" is the name of the sub_umbrella framework.  When
+   * staticly linking when -twolevel_namespace is in effect a twolevel namespace
+   * umbrella framework will only cause its subframeworks and those frameworks
+   * listed as sub_umbrella frameworks to be implicited linked in.  Any other
+   * dependent dynamic libraries will not be linked it when -twolevel_namespace
+   * is in effect.  The primary library recorded by the static linker when
+   * resolving a symbol in these libraries will be the umbrella framework.
+   * Zero or more sub_umbrella frameworks may be use by an umbrella framework.
+   * The name of a sub_umbrella framework is recorded in the following structure.
+    }
+  
+  sub_umbrella_command = record
+    cmd           : uint32_t; { LC_SUB_UMBRELLA  }                
+    cmdsize       : uint32_t; { includes sub_umbrella string  }   
+    sub_umbrella  : lc_str;   { the sub_umbrella framework name  }
+  end;
+
+  {* A dynamically linked shared library may be a sub_library of another shared
+   * library.  If so it will be linked with "-sub_library library_name" where
+   * Where "library_name" is the name of the sub_library shared library.  When
+   * staticly linking when -twolevel_namespace is in effect a twolevel namespace
+   * shared library will only cause its subframeworks and those frameworks
+   * listed as sub_umbrella frameworks and libraries listed as sub_libraries to
+   * be implicited linked in.  Any other dependent dynamic libraries will not be
+   * linked it when -twolevel_namespace is in effect.  The primary library
+   * recorded by the static linker when resolving a symbol in these libraries
+   * will be the umbrella framework (or dynamic library). Zero or more sub_library
+   * shared libraries may be use by an umbrella framework or (or dynamic library).
+   * The name of a sub_library framework is recorded in the following structure.
+   * For example /usr/lib/libobjc_profile.A.dylib would be recorded as "libobjc".}
+   
+  sub_library_command = record
+    cmd         : uint32_t; { LC_SUB_LIBRARY  }             
+    cmdsize     : uint32_t; { includes sub_library string  }
+    sub_library : lc_str;   { the sub_library name  }       
+  end;
+  psub_library_command = ^sub_library_command;
+
+  {* A program (filetype == MH_EXECUTE) that is
+   * prebound to its dynamic libraries has one of these for each library that
+   * the static linker used in prebinding.  It contains a bit vector for the
+   * modules in the library.  The bits indicate which modules are bound (1) and
+   * which are not (0) from the library.  The bit for module 0 is the low bit
+   * of the first byte.  So the bit for the Nth module is:
+   * (linked_modules[N/8] >> N%8) & 1 }
+  
+  prebound_dylib_command = record
+    cmd      : uint32_t;     { LC_PREBOUND_DYLIB  }           
+    cmdsize  : uint32_t;     { includes strings  }            
+    name     : lc_str;       { library's path name  }         
+    nmodules : uint32_t;     { number of modules in library  }
+    linked_modules : lc_str; { bit vector of linked modules  }
+  end;
+  pprebound_dylib_command = ^prebound_dylib_command;
+       
+       
+  {* A program that uses a dynamic linker contains a dylinker_command to identify
+   * the name of the dynamic linker (LC_LOAD_DYLINKER).  And a dynamic linker
+   * contains a dylinker_command to identify the dynamic linker (LC_ID_DYLINKER).
+   * A file can have at most one of these.}
+  
+  dylinker_command = record
+    cmd     : uint32_t; { LC_ID_DYLINKER or LC_LOAD_DYLINKER  }
+    cmdsize : uint32_t; { includes pathname string  }          
+    name    : lc_str;   { dynamic linker's path name  }        
+  end;
+  pdylinker_command = ^dylinker_command;
+  
+  {
+   * Thread commands contain machine-specific data structures suitable for
+   * use in the thread state primitives.  The machine specific data structures
+   * follow the struct thread_command as follows.
+   * Each flavor of machine specific data structure is preceded by an unsigned
+   * long constant for the flavor of that data structure, an uint32_t
+   * that is the count of longs of the size of the state data structure and then
+   * the state data structure follows.  This triple may be repeated for many
+   * flavors.  The constants for the flavors, counts and state data structure
+   * definitions are expected to be in the header file <machine/thread_status.h>.
+   * These machine specific data structures sizes must be multiples of
+   * 4 bytes  The cmdsize reflects the total size of the thread_command
+   * and all of the sizes of the constants for the flavors, counts and state
+   * data structures.
+   *
+   * For executable objects that are unix processes there will be one
+   * thread_command (cmd == LC_UNIXTHREAD) created for it by the link-editor.
+   * This is the same as a LC_THREAD, except that a stack is automatically
+   * created (based on the shell's limit for the stack size).  Command arguments
+   * and environment variables are copied onto that stack.
+    }
+  
+  thread_command = record
+    cmd     : uint32_t; { LC_THREAD or  LC_UNIXTHREAD  }                                        
+    cmdsize : uint32_t; { total size of this command  }                                  
+    flavor  : uint32_t; { uint32_t flavor		   flavor of thread state  }                 
+    count   : uint32_t; { uint32_t count		   count of longs in thread state  }         
+                        { struct XXX_thread_state state   thread state for this flavor  }
+                        { ...  }                                                         
+  end;
+  pthread_command = ^thread_command;
+
+  {* The routines command contains the address of the dynamic shared library
+   * initialization routine and an index into the module table for the module
+   * that defines the routine.  Before any modules are used from the library the
+   * dynamic linker fully binds the module that defines the initialization routine
+   * and then calls it.  This gets called before any module initialization
+   * routines (used for C++ static constructors) in the library.  }
+  { for 32-bit architectures  }
+  
+  routines_command = record
+    cmd     : uint32_t;       { LC_ROUTINES  }                      
+    cmdsize : uint32_t;       { total size of this command  }       
+    init_address : uint32_t;  { address of initialization routine  }
+    init_module  : uint32_t;  { index into the module table that the init routine is defined in }
+    reserved1 : uint32_t;
+    reserved2 : uint32_t;
+    reserved3 : uint32_t;
+    reserved4 : uint32_t;
+    reserved5 : uint32_t;
+    reserved6 : uint32_t;
+  end;
+  proutines_command = ^routines_command;
+
+  { * The 64-bit routines command.  Same use as above. }
+  { for 64-bit architectures  }
+  
+  routines_command_64 = record
+    cmd     : uint32_t;         { LC_ROUTINES_64  }                   
+    cmdsize : uint32_t;         { total size of this command  }       
+    init_address : uint64_t;    { address of initialization routine  }
+    init_module  : uint64_t;    { index into the module table that  } 
+                                {  the init routine is defined in  }  
+    reserved1 : uint64_t;
+    reserved2 : uint64_t;
+    reserved3 : uint64_t;
+    reserved4 : uint64_t;
+    reserved5 : uint64_t;
+    reserved6 : uint64_t;
+  end;
+  proutines_command_64 = ^routines_command_64;
+
+  {* The symtab_command contains the offsets and sizes of the link-edit 4.3BSD
+   * "stab" style symbol table information as described in the header files
+   * <nlist.h> and <stab.h>.
+    }
+
+  symtab_command = record
+    cmd     : uint32_t;  { LC_SYMTAB  }                       
+    cmdsize : uint32_t;  { sizeof(struct symtab_command)  }   
+    symoff  : uint32_t;  { symbol table offset  }             
+    nsyms   : uint32_t;  { number of symbol table entries  }  
+    stroff  : uint32_t;  { string table offset  }             
+    strsize : uint32_t;  { string table size in bytes  }      
+  end;
+  psymtab_command = ^symtab_command;
+
+  {
+   * This is the second set of the symbolic information which is used to support
+   * the data structures for the dynamically link editor.
+   *
+   * The original set of symbolic information in the symtab_command which contains
+   * the symbol and string tables must also be present when this load command is
+   * present.  When this load command is present the symbol table is organized
+   * into three groups of symbols:
+   *	local symbols (static and debugging symbols) - grouped by module
+   *	defined external symbols - grouped by module (sorted by name if not lib)
+   *	undefined external symbols (sorted by name if MH_BINDATLOAD is not set,
+   *	     			    and in order the were seen by the static
+   *				    linker if MH_BINDATLOAD is set)
+   * In this load command there are offsets and counts to each of the three groups
+   * of symbols.
+   *
+   * This load command contains a the offsets and sizes of the following new
+   * symbolic information tables:
+   *	table of contents
+   *	module table
+   *	reference symbol table
+   *	indirect symbol table
+   * The first three tables above (the table of contents, module table and
+   * reference symbol table) are only present if the file is a dynamically linked
+   * shared library.  For executable and object modules, which are files
+   * containing only one module, the information that would be in these three
+   * tables is determined as follows:
+   * 	table of contents - the defined external symbols are sorted by name
+   *	module table - the file contains only one module so everything in the
+   *		       file is part of the module.
+   *	reference symbol table - is the defined and undefined external symbols
+   *
+   * For dynamically linked shared library files this load command also contains
+   * offsets and sizes to the pool of relocation entries for all sections
+   * separated into two groups:
+   *	external relocation entries
+   *	local relocation entries
+   * For executable and object modules the relocation entries continue to hang
+   * off the section structures.
+    }
+
+  dysymtab_command = record
+    cmd             : uint32_t; { LC_DYSYMTAB  }
+    cmdsize         : uint32_t; { sizeof(struct dysymtab_command)  }
+  {
+       * The symbols indicated by symoff and nsyms of the LC_SYMTAB load command
+       * are grouped into the following three groups:
+       *    local symbols (further grouped by the module they are from)
+       *    defined external symbols (further grouped by the module they are from)
+       *    undefined symbols
+       *
+       * The local symbols are used only for debugging.  The dynamic binding
+       * process may have to use them to indicate to the debugger the local
+       * symbols for a module that is being bound.
+       *
+       * The last two groups are used by the dynamic binding process to do the
+       * binding (indirectly through the module table and the reference symbol
+       * table when this is a dynamically linked shared library file).
+        }
+    ilocalsym       : uint32_t; { index to local symbols  }
+    nlocalsym       : uint32_t; { number of local symbols  }
+    iextdefsym      : uint32_t; { index to externally defined symbols  }
+    nextdefsym      : uint32_t; { number of externally defined symbols  }
+    iundefsym       : uint32_t; { index to undefined symbols  }
+    nundefsym       : uint32_t; { number of undefined symbols  }
+  {
+       * For the for the dynamic binding process to find which module a symbol
+       * is defined in the table of contents is used (analogous to the ranlib
+       * structure in an archive) which maps defined external symbols to modules
+       * they are defined in.  This exists only in a dynamically linked shared
+       * library file.  For executable and object modules the defined external
+       * symbols are sorted by name and is use as the table of contents.
+        }
+    tocoff          : uint32_t; { file offset to table of contents  }
+    ntoc            : uint32_t; { number of entries in table of contents  }
+  {
+       * To support dynamic binding of "modules" (whole object files) the symbol
+       * table must reflect the modules that the file was created from.  This is
+       * done by having a module table that has indexes and counts into the merged
+       * tables for each module.  The module structure that these two entries
+       * refer to is described below.  This exists only in a dynamically linked
+       * shared library file.  For executable and object modules the file only
+       * contains one module so everything in the file belongs to the module.
+        }
+    modtaboff       : uint32_t; { file offset to module table  }
+    nmodtab         : uint32_t; { number of module table entries  }
+  {
+       * To support dynamic module binding the module structure for each module
+       * indicates the external references (defined and undefined) each module
+       * makes.  For each module there is an offset and a count into the
+       * reference symbol table for the symbols that the module references.
+       * This exists only in a dynamically linked shared library file.  For
+       * executable and object modules the defined external symbols and the
+       * undefined external symbols indicates the external references.
+        }
+    extrefsymoff    : uint32_t; { offset to referenced symbol table  }
+    nextrefsyms     : uint32_t; { number of referenced symbol table entries  }
+  {
+       * The sections that contain "symbol pointers" and "routine stubs" have
+       * indexes and (implied counts based on the size of the section and fixed
+       * size of the entry) into the "indirect symbol" table for each pointer
+       * and stub.  For every section of these two types the index into the
+       * indirect symbol table is stored in the section header in the field
+       * reserved1.  An indirect symbol table entry is simply a 32bit index into
+       * the symbol table to the symbol that the pointer or stub is referring to.
+       * The indirect symbol table is ordered to match the entries in the section.
+        }
+    indirectsymoff  : uint32_t; { file offset to the indirect symbol table  }
+    nindirectsyms   : uint32_t; { number of indirect symbol table entries  }
+  {    * To support relocating an individual module in a library file quickly the
+       * external relocation entries for each module in the library need to be
+       * accessed efficiently.  Since the relocation entries can't be accessed
+       * through the section headers for a library file they are separated into
+       * groups of local and external entries further grouped by module.  In this
+       * case the presents of this load command who's extreloff, nextrel,
+       * locreloff and nlocrel fields are non-zero indicates that the relocation
+       * entries of non-merged sections are not referenced through the section
+       * structures (and the reloff and nreloc fields in the section headers are
+       * set to zero).
+       *
+       * Since the relocation entries are not accessed through the section headers
+       * this requires the r_address field to be something other than a section
+       * offset to identify the item to be relocated.  In this case r_address is
+       * set to the offset from the vmaddr of the first LC_SEGMENT command.
+       * For MH_SPLIT_SEGS images r_address is set to the the offset from the
+       * vmaddr of the first read-write LC_SEGMENT command.
+       *
+       * The relocation entries are grouped by module and the module table
+       * entries have indexes and counts into them for the group of external
+       * relocation entries for that the module.
+       *
+       * For sections that are merged across modules there must not be any
+       * remaining external relocation entries for them (for merged sections
+       * remaining relocation entries must be local).
+        }
+    extreloff       : uint32_t; { offset to external relocation entries  }
+    nextrel         : uint32_t; { number of external relocation entries  }
+    {   * All the local relocation entries are grouped together (they are not
+       * grouped by their module since they are only used if the object is moved
+       * from it staticly link edited address).      }
+    locreloff       : uint32_t; { offset to local relocation entries  }
+    nlocrel         : uint32_t; { number of local relocation entries  }
+  end;
+
+  {
+   * An indirect symbol table entry is simply a 32bit index into the symbol table
+   * to the symbol that the pointer or stub is refering to.  Unless it is for a
+   * non-lazy symbol pointer section for a defined symbol which strip(1) as
+   * removed.  In which case it has the value INDIRECT_SYMBOL_LOCAL.  If the
+   * symbol was also absolute INDIRECT_SYMBOL_ABS is or'ed with that.
+    }
+
+const
+  INDIRECT_SYMBOL_LOCAL = $80000000;
+  INDIRECT_SYMBOL_ABS = $40000000;
+
+type
+  dylib_table_of_contents = record { a table of contents entry  }
+    symbol_index : uint32_t; { the defined external symbol (index into the symbol table)  }
+    module_index : uint32_t; { index into the module table this symbol is defined in  }
+  end;
+
+  dylib_module = record     { a module table entry  }
+    module_name : uint32_t; { the module name (index into string table)  }
+    iextdefsym  : uint32_t; { index into externally defined symbols  }
+    nextdefsym  : uint32_t; { number of externally defined symbols  }
+    irefsym     : uint32_t; { index into reference symbol table  }
+    nrefsym     : uint32_t; { number of reference symbol table entries  }
+    ilocalsym   : uint32_t; { index into symbols for local symbols  }
+    nlocalsym   : uint32_t; { number of local symbols  }
+    iextrel     : uint32_t; { index into external relocation entries  }
+    nextrel     : uint32_t; { number of external relocation entries  }
+    iinit_iterm : uint32_t; { low 16 bits are the index into the init
+  				   section, high 16 bits are the index into
+  			           the term section  }
+    ninit_nterm : uint32_t; { low 16 bits are the number of init section
+  				   entries, high 16 bits are the number of
+  				   term section entries  }
+    objc_module_info_addr : uint32_t;  { for this module address of the start of the (__OBJC,__module_info) section  }
+    objc_module_info_size : uint32_t;  { for this module size of  the (__OBJC,__module_info) section  }
+  end;
+
+  dylib_module_64 = record   { a 64-bit module table entry  }
+    module_name : uint32_t;  { the module name (index into string table)  }
+    iextdefsym  : uint32_t;  { index into externally defined symbols  }
+    nextdefsym  : uint32_t;  { number of externally defined symbols  }
+    irefsym     : uint32_t;  { index into reference symbol table  }
+    nrefsym     : uint32_t;  { number of reference symbol table entries  }
+    ilocalsym   : uint32_t;  { index into symbols for local symbols  }
+    nlocalsym   : uint32_t;  { number of local symbols  }
+    iextrel     : uint32_t;  { index into external relocation entries  }
+    nextrel     : uint32_t;  { number of external relocation entries  }
+    iinit_iterm : uint32_t;  { low 16 bits are the index into the init
+                    				   section, high 16 bits are the index into
+                    				   the term section  }
+    ninit_nterm : uint32_t; { low 16 bits are the number of init section
+                    				  entries, high 16 bits are the number of
+                    				  term section entries  }
+    objc_module_info_size : uint32_t; { for this module size of the (__OBJC,__module_info) section  }
+    objc_module_info_addr : uint64_t; { for this module address of the start of the (__OBJC,__module_info) section  }
+  end;
+
+  {
+   * The entries in the reference symbol table are used when loading the module
+   * (both by the static and dynamic link editors) and if the module is unloaded
+   * or replaced.  Therefore all external symbols (defined and undefined) are
+   * listed in the module's reference table.  The flags describe the type of
+   * reference that is being made.  The constants for the flags are defined in
+   * <mach-o/nlist.h> as they are also used for symbol table entries.
+    }
+  { index into the symbol table  }
+  { flags to indicate the type of reference  }
+  dylib_reference = record
+    flag0 : longint;
+  end;
+
+
+{  const
+     bm_dylib_reference_isym = $FFFFFF;
+     bp_dylib_reference_isym = 0;
+     bm_dylib_reference_flags = $FF000000;
+     bp_dylib_reference_flags = 24;
+
+  function isym(var a : dylib_reference) : uint32_t;
+  procedure set_isym(var a : dylib_reference; __isym : uint32_t);
+  function flags(var a : dylib_reference) : uint32_t;
+  procedure set_flags(var a : dylib_reference; __flags : uint32_t);}
+
+  {* The twolevel_hints_command contains the offset and number of hints in the
+   * two-level namespace lookup hints table.}
+ 
+type
+  twolevel_hints_command = record
+    cmd     : uint32_t; { LC_TWOLEVEL_HINTS  }                    
+    cmdsize : uint32_t; { sizeof(struct twolevel_hints_command)  }
+    offset  : uint32_t; { offset to the hint table  }             
+    nhints  : uint32_t; { number of hints in the hint table  }    
+  end;
+
+  {
+   * The entries in the two-level namespace lookup hints table are twolevel_hint
+   * structs.  These provide hints to the dynamic link editor where to start
+   * looking for an undefined symbol in a two-level namespace image.  The
+   * isub_image field is an index into the sub-images (sub-frameworks and
+   * sub-umbrellas list) that made up the two-level image that the undefined
+   * symbol was found in when it was built by the static link editor.  If
+   * isub-image is 0 the the symbol is expected to be defined in library and not
+   * in the sub-images.  If isub-image is non-zero it is an index into the array
+   * of sub-images for the umbrella with the first index in the sub-images being
+   * 1. The array of sub-images is the ordered list of sub-images of the umbrella
+   * that would be searched for a symbol that has the umbrella recorded as its
+   * primary library.  The table of contents index is an index into the
+   * library's table of contents.  This is used as the starting point of the
+   * binary search or a directed linear search.
+    }
+  { index into the sub images  }
+  { index into the table of contents  }
+  twolevel_hint = record
+    flag0 : longint;
+  end;
+
+
+{  const
+     bm_twolevel_hint_isub_image = $FF;
+     bp_twolevel_hint_isub_image = 0;
+     bm_twolevel_hint_itoc = $FFFFFF00;
+     bp_twolevel_hint_itoc = 8;
+
+  function isub_image(var a : twolevel_hint) : uint32_t;
+  procedure set_isub_image(var a : twolevel_hint; __isub_image : uint32_t);
+  function itoc(var a : twolevel_hint) : uint32_t;
+  procedure set_itoc(var a : twolevel_hint; __itoc : uint32_t);
+}
+
+type
+  {* The prebind_cksum_command contains the value of the original check sum for
+   * prebound files or zero.  When a prebound file is first created or modified
+   * for other than updating its prebinding information the value of the check sum
+   * is set to zero.  When the file has it prebinding re-done and if the value of
+   * the check sum is zero the original check sum is calculated and stored in
+   * cksum field of this load command in the output file.  If when the prebinding
+   * is re-done and the cksum field is non-zero it is left unchanged from the
+   * input file. }
+   
+  prebind_cksum_command = record
+    cmd     : uint32_t; { LC_PREBIND_CKSUM  }                    
+    cmdsize : uint32_t; { sizeof(struct prebind_cksum_command)  }
+    cksum   : uint32_t; { the check sum or zero  }               
+  end;
+  pprebind_cksum_command = ^prebind_cksum_command;
+  
+       
+  {* The uuid load command contains a single 128-bit unique random number that
+   * identifies an object produced by the static link editor. }
+
+  uuid_command = record                
+    cmd     : uint32_t;                { LC_UUID  }                    
+    cmdsize : uint32_t;                { sizeof(struct uuid_command)  }
+    uuid    : array[0..15] of uint8_t; { the 128-bit uuid  }           
+  end;
+  puuid_command = ^uuid_command;
+  
+  
+  {* The rpath_command contains a path which at runtime should be added to
+   * the current run path used to find @rpath prefixed dylibs.}
+    
+  rpath_command = record
+    cmd     : uint32_t; { LC_RPATH  }               
+    cmdsize : uint32_t; { includes string  }        
+    path    : lc_str;   { path to add to run path  }
+  end;
+  prpath_command = ^rpath_command;
+
+  
+  {* The linkedit_data_command contains the offsets and sizes of a blob
+   * of data in the __LINKEDIT segment.}
+  
+  linkedit_data_command = record
+    cmd      : uint32_t; { LC_CODE_SIGNATURE or LC_SEGMENT_SPLIT_INFO  }
+    cmdsize  : uint32_t; { sizeof(struct linkedit_data_command)  }      
+    dataoff  : uint32_t; { file offset of data in __LINKEDIT segment  } 
+    datasize : uint32_t; { file size of data in __LINKEDIT segment   }  
+  end;
+  plinkedit_data_command = ^linkedit_data_command;
+  
+  
+  {* The encryption_info_command contains the file offset and size of an
+   * of an encrypted segment.}
+  
+  encryption_info_command = record
+    cmd       : uint32_t; { LC_ENCRYPTION_INFO  }                               
+    cmdsize   : uint32_t; { sizeof(struct encryption_info_command)  }           
+    cryptoff  : uint32_t; { file offset of encrypted range  }                   
+    cryptsize : uint32_t; { file size of encrypted range  }                     
+    cryptid   : uint32_t; { which enryption system, 0 means not-encrypted yet  }
+  end;
+  pencryption_info_command = ^encryption_info_command;
+  
+  
+  {* The symseg_command contains the offset and size of the GNU style
+   * symbol table information as described in the header file <symseg.h>.
+   * The symbol roots of the symbol segments must also be aligned properly
+   * in the file.  So the requirement of keeping the offsets aligned to a
+   * multiple of a 4 bytes translates to the length field of the symbol
+   * roots also being a multiple of a long.  Also the padding must again be
+   * zeroed. (THIS IS OBSOLETE and no longer supported). }
+  
+  symseg_command = record
+    cmd     : uint32_t; { LC_SYMSEG  }                    
+    cmdsize : uint32_t; { sizeof(struct symseg_command)  }
+    offset  : uint32_t; { symbol segment offset  }        
+    size    : uint32_t; { symbol segment size in bytes  } 
+  end;
+  psymseg_command = ^symseg_command;
+
+
+  {* The ident_command contains a free format string table following the
+   * ident_command structure.  The strings are null terminated and the size of
+   * the command is padded out with zero bytes to a multiple of 4 bytes/
+   * (THIS IS OBSOLETE and no longer supported).}
+  
+  ident_command = record
+    cmd     : uint32_t; { LC_IDENT  }                        
+    cmdsize : uint32_t; { strings that follow this command  }
+  end;
+  pident_command = ^ident_command;
+  
+  
+  {* The fvmfile_command contains a reference to a file to be loaded at the
+   * specified virtual address.  (Presently, this command is reserved for
+   * internal use.  The kernel ignores this command when loading a program into
+   * memory).  }
+  
+  fvmfile_command = record
+    cmd         : uint32_t;  { LC_FVMFILE  }              
+    cmdsize     : uint32_t;  { includes pathname string  }
+    name        : lc_str;    { files pathname  }          
+    header_addr : uint32_t;  { files virtual address  }   
+  end;
+  pfvmfile_command = ^fvmfile_command;
+
+  
+  {* This header file describes the structures of the file format for "fat"
+   * architecture specific file (wrapper design).  At the begining of the file
+   * there is one fat_header structure followed by a number of fat_arch
+   * structures.  For each architecture in the file, specified by a pair of
+   * cputype and cpusubtype, the fat_header describes the file offset, file
+   * size and alignment in the file of the architecture specific member.
+   * The padded bytes in the file to place each member on it's specific alignment
+   * are defined to be read as zeros and can be left as "holes" if the file system
+   * can support them as long as they read as zeros.
+   *
+   * All structures defined here are always written and read to/from disk
+   * in big-endian order.}
+  {* <mach/machine.h> is needed here for the cpu_type_t and cpu_subtype_t types
+   * and contains the constants for the possible values of these types.}
+
+const
+  FAT_MAGIC = $cafebabe;
+  FAT_CIGAM = $bebafeca;
+
+type
+  fat_header = record
+    magic       : uint32_t;      { FAT_MAGIC  }
+    nfat_arch   : uint32_t;      { number of structs that follow  }
+  end;
+
+  fat_arch = record
+    cputype     : cpu_type_t;    { cpu specifier (int)  }
+    cpusubtype  : cpu_subtype_t; { machine specifier (int)  }
+    offset      : uint32_t;      { file offset to this object file  }
+    size        : uint32_t;      { size of this object file  }
+    align       : uint32_t;      { alignment as a power of 2  }
+  end;
+
+
+  {
+   * Format of a symbol table entry of a Mach-O file for 32-bit architectures.
+   * Modified from the BSD format.  The modifications from the original format
+   * were changing n_other (an unused field) to n_sect and the addition of the
+   * N_SECT type.  These modifications are required to support symbols in a larger
+   * number of sections not just the three sections (text, data and bss) in a BSD
+   * file.
+    }
+
+type
+  nlist = record
+    n_un : record
+    case longint of
+      {$ifndef __LP64__}
+      0 : ( n_name : Pchar );   { for use when in-core }
+      {$endif}
+      1 : ( n_strx : int32_t ); { index into the string table  }
+    end;
+    n_type  : uint8_t;  { type flag, see below  }
+    n_sect  : uint8_t;  { section number or NO_SECT  }
+    n_desc  : int16_t;  { see <mach-o/stab.h>  }
+    n_value : uint32_t; { value of this symbol (or stab offset)  }
+  end;
+  pnlist = ^nlist;
+
+  {* This is the symbol table entry structure for 64-bit architectures.}
+  nlist_64 = record
+    n_un : record
+    case longint of
+      0 : ( n_strx : uint32_t ); { index into the string table  }
+    end;
+    n_type  : uint8_t;  { type flag, see below  }
+    n_sect  : uint8_t;  { section number or NO_SECT  }
+    n_desc  : uint16_t; { see <mach-o/stab.h>  }
+    n_value : uint64_t; { value of this symbol (or stab offset)  }
+  end;
+  pnlist_64 = ^nlist_64;
+
+  {* Symbols with a index into the string table of zero (n_un.n_strx == 0) are
+   * defined to have a null, "", name.  Therefore all string indexes to non null
+   * names must not have a zero string index.  This is bit historical information
+   * that has never been well documented. }
+  {* The n_type field really contains four fields:
+   *	unsigned char N_STAB:3,
+   *		      N_PEXT:1,
+   *		      N_TYPE:3,
+   *		      N_EXT:1;
+   * which are used via the following masks.}
+
+const
+  N_STAB = $e0; { if any of these bits set, a symbolic debugging entry  }
+  N_PEXT = $10; { private external symbol bit  }
+  N_TYPE = $0e; { mask for the type bits  }
+  N_EXT  = $01; { external symbol bit, set for external symbols  }
+
+  {* Only symbolic debugging entries have some of the N_STAB bits set and if any
+   * of these bits are set then it is a symbolic debugging entry (a stab).  In
+   * which case then the values of the n_type field (the entire field) are given
+   * in <mach-o/stab.h> }
+
+  {* Values for N_TYPE bits of the n_type field. }
+
+  N_UNDF = $0; { undefined, n_sect == NO_SECT  }
+  N_ABS  = $2; { absolute, n_sect == NO_SECT  }
+  N_SECT = $e; { defined in section number n_sect  }
+  N_PBUD = $c; { prebound undefined (defined in a dylib)  }
+  N_INDR = $a; { indirect  }
+
+  {* If the type is N_INDR then the symbol is defined to be the same as another
+   * symbol.  In this case the n_value field is an index into the string table
+   * of the other symbol's name.  When the other symbol is defined then they both
+   * take on the defined type and value.}
+
+  {* If the type is N_SECT then the n_sect field contains an ordinal of the
+   * section the symbol is defined in.  The sections are numbered from 1 and
+   * refer to sections in order they appear in the load commands for the file
+   * they are in.  This means the same ordinal may very well refer to different
+   * sections in different files.
+   *
+   * The n_value field for all symbol table entries (including N_STAB's) gets
+   * updated by the link editor based on the value of it's n_sect field and where
+   * the section n_sect references gets relocated.  If the value of the n_sect
+   * field is NO_SECT then it's n_value field is not changed by the link editor.}
+
+  NO_SECT = 0;    { symbol is not in any section  }
+  MAX_SECT = 255; { 1 thru 255 inclusive  }
+  {* Common symbols are represented by undefined (N_UNDF) external (N_EXT) types
+   * who's values (n_value) are non-zero.  In which case the value of the n_value
+   * field is the size (in bytes) of the common symbol.  The n_sect field is set
+   * to NO_SECT.  The alignment of a common symbol may be set as a power of 2
+   * between 2^1 and 2^15 as part of the n_desc field using the macros below. If
+   * the alignment is not set (a value of zero) then natural alignment based on
+   * the size is used.}
+
+  { ----- Process manually -----
+  #define GET_COMM_ALIGN(n_desc) (((n_desc) >> 8) & 0x0f)
+  #define SET_COMM_ALIGN(n_desc,align) \
+      (n_desc) = (((n_desc) & 0xf0ff) | (((align) & 0x0f) << 8))
+   }
+
+  {* To support the lazy binding of undefined symbols in the dynamic link-editor,
+   * the undefined symbols in the symbol table (the nlist structures) are marked
+   * with the indication if the undefined reference is a lazy reference or
+   * non-lazy reference.  If both a non-lazy reference and a lazy reference is
+   * made to the same symbol the non-lazy reference takes precedence.  A reference
+   * is lazy only when all references to that symbol are made through a symbol
+   * pointer in a lazy symbol pointer section.
+   *
+   * The implementation of marking nlist structures in the symbol table for
+   * undefined symbols will be to use some of the bits of the n_desc field as a
+   * reference type.  The mask REFERENCE_TYPE will be applied to the n_desc field
+   * of an nlist structure for an undefined symbol to determine the type of
+   * undefined reference (lazy or non-lazy).
+   *
+   * The constants for the REFERENCE FLAGS are propagated to the reference table
+   * in a shared library file.  In that case the constant for a defined symbol,
+   * REFERENCE_FLAG_DEFINED, is also used.}
+
+  { Reference type bits of the n_desc field of undefined symbols  }
+  REFERENCE_TYPE = $7;
+
+  { types of references  }
+  REFERENCE_FLAG_UNDEFINED_NON_LAZY = 0;
+  REFERENCE_FLAG_UNDEFINED_LAZY = 1;
+  REFERENCE_FLAG_DEFINED = 2;
+  REFERENCE_FLAG_PRIVATE_DEFINED = 3;
+  REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY = 4;
+  REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY = 5;
+
+  {* To simplify stripping of objects that use are used with the dynamic link
+   * editor, the static link editor marks the symbols defined an object that are
+   * referenced by a dynamicly bound object (dynamic shared libraries, bundles).
+   * With this marking strip knows not to strip these symbols.}
+  REFERENCED_DYNAMICALLY = $0010;
+
+  {* For images created by the static link editor with the -twolevel_namespace
+   * option in effect the flags field of the mach header is marked with
+   * MH_TWOLEVEL.  And the binding of the undefined references of the image are
+   * determined by the static link editor.  Which library an undefined symbol is
+   * bound to is recorded by the static linker in the high 8 bits of the n_desc
+   * field using the SET_LIBRARY_ORDINAL macro below.  The ordinal recorded
+   * references the libraries listed in the Mach-O's LC_LOAD_DYLIB load commands
+   * in the order they appear in the headers.   The library ordinals start from 1.
+   * For a dynamic library that is built as a two-level namespace image the
+   * undefined references from module defined in another use the same nlist struct
+   * an in that case SELF_LIBRARY_ORDINAL is used as the library ordinal.  For
+   * defined symbols in all images they also must have the library ordinal set to
+   * SELF_LIBRARY_ORDINAL.  The EXECUTABLE_ORDINAL refers to the executable
+   * image for references from plugins that refer to the executable that loads
+   * them.
+   *
+   * The DYNAMIC_LOOKUP_ORDINAL is for undefined symbols in a two-level namespace
+   * image that are looked up by the dynamic linker with flat namespace semantics.
+   * This ordinal was added as a feature in Mac OS X 10.3 by reducing the
+   * value of MAX_LIBRARY_ORDINAL by one.  So it is legal for existing binaries
+   * or binaries built with older tools to have 0xfe (254) dynamic libraries.  In
+   * this case the ordinal value 0xfe (254) must be treated as a library ordinal
+   * for compatibility.}
+
+  { was #define dname(params) para_def_expr }
+  { argument types are unknown }
+  { return type might be wrong }
+//  function GET_LIBRARY_ORDINAL(n_desc : longint) : longint;
+
+  { -- Process Manually ---
+  #define SET_LIBRARY_ORDINAL(n_desc,ordinal) \
+  	(n_desc) = (((n_desc) & 0x00ff) | (((ordinal) & 0xff) << 8))
+   }
+
+const
+  SELF_LIBRARY_ORDINAL   = $0;
+  MAX_LIBRARY_ORDINAL    = $fd;
+  DYNAMIC_LOOKUP_ORDINAL = $fe;
+  EXECUTABLE_ORDINAL     = $ff;
+
+  {* The bit 0x0020 of the n_desc field is used for two non-overlapping purposes
+   * and has two different symbolic names, N_NO_DEAD_STRIP and N_DESC_DISCARDED. }
+
+  {* The N_NO_DEAD_STRIP bit of the n_desc field only ever appears in a
+   * relocatable .o file (MH_OBJECT filetype). And is used to indicate to the
+   * static link editor it is never to dead strip the symbol.}
+  N_NO_DEAD_STRIP = $0020; { symbol is not to be dead stripped  }
+
+
+
+  {* The N_DESC_DISCARDED bit of the n_desc field never appears in linked image.
+   * But is used in very rare cases by the dynamic link editor to mark an in
+   * memory symbol as discared and longer used for linking. }
+  N_DESC_DISCARDED = $0020; { symbol is discarded  }
+
+  {* The N_WEAK_REF bit of the n_desc field indicates to the dynamic linker that
+   * the undefined symbol is allowed to be missing and is to have the address of
+   * zero when missing. }
+  N_WEAK_REF = $0040; { symbol is weak referenced  }
+
+  {* The N_WEAK_DEF bit of the n_desc field indicates to the static and dynamic
+   * linkers that the symbol definition is weak, allowing a non-weak symbol to
+   * also be used which causes the weak definition to be discared.  Currently this
+   * is only supported for symbols in coalesed sections. }
+  N_WEAK_DEF = $0080; { coalesed symbol is a weak definition  }
+
+  {* The N_REF_TO_WEAK bit of the n_desc field indicates to the dynamic linker
+   * that the undefined symbol should be resolved using flat namespace searching. }
+  N_REF_TO_WEAK = $0080; { reference to a weak symbol  }
+
+  {* The N_ARM_THUMB_DEF bit of the n_desc field indicates that the symbol is
+   * a defintion of a Thumb function. }
+  N_ARM_THUMB_DEF = $0008; { symbol is a Thumb function (ARM)  }
+
+  {* There are two known orders of table of contents for archives.  The first is
+   * the order ranlib(1) originally produced and still produces without any
+   * options.  This table of contents has the archive member name "__.SYMDEF"
+   * This order has the ranlib structures in the order the objects appear in the
+   * archive and the symbol names of those objects in the order of symbol table.
+   * The second know order is sorted by symbol name and is produced with the -s
+   * option to ranlib(1).  This table of contents has the archive member name
+   * "__.SYMDEF SORTED" and many programs (notably the 1.0 version of ld(1) can't
+   * tell the difference between names because of the imbedded blank in the name
+   * and works with either table of contents).  This second order is used by the
+   * post 1.0 link editor to produce faster linking.  The original 1.0 version of
+   * ranlib(1) gets confused when it is run on a archive with the second type of
+   * table of contents because it and ar(1) which it uses use different ways to
+   * determined the member name (ar(1) treats all blanks in the name as
+   * significant and ranlib(1) only checks for the first one).}
+
+const
+  SYMDEF = '__.SYMDEF';
+  SYMDEF_SORTED = '__.SYMDEF SORTED';
+
+  {
+   * Structure of the __.SYMDEF table of contents for an archive.
+   * __.SYMDEF begins with a long giving the size in bytes of the ranlib
+   * structures which immediately follow, and then continues with a string
+   * table consisting of a long giving the number of bytes of strings which
+   * follow and then the strings themselves.  The ran_strx fields index the
+   * string table whose first byte is numbered 0.
+    }
+
+type
+  ranlib = record
+    ran_un : record
+      case longint of
+        0 : ( ran_strx : uint32_t );
+        1 : ( ran_name : ^char );
+      end;
+    ran_off : uint32_t;
+  end;
+
+type
+   {* Format of a relocation entry of a Mach-O file.  Modified from the 4.3BSD
+   * format.  The modifications from the original format were changing the value
+   * of the r_symbolnum field for "local" (r_extern == 0) relocation entries.
+   * This modification is required to support symbols in an arbitrary number of
+   * sections not just the three sections (text, data and bss) in a 4.3BSD file.
+   * Also the last 4 bits have had the r_type tag added to them. }
+
+  relocation_info = record
+    r_address : int32_t;  { offset in the section to what is being relocated  }
+    r_info    : longint;
+    // r_symbolnum:24,	{* symbol index if r_extern == 1 or section  ordinal if r_extern == 0 *}
+		// r_pcrel:1; 	    {* was relocated pc relative already *}
+ 		// r_length:2;	    {* 0=byte, 1=word, 2=long, 3=quad *}
+ 		// r_extern:1;     	{* does not include value of sym referenced *}
+	 	// r_type:4; 	      {* if not 0, machine specific relocation type *}
+  end;
+
+
+{ absolute relocation type for Mach-O files  }
+
+const
+  R_ABS = 0;
+  R_SCATTERED = $80000000;   { mask to be applied to the r_address field }
+            { of a relocation_info structure to tell that }
+  				  { is is really a scattered_relocation_info }
+  				  { stucture  }
+
+  {
+   * The r_address is not really the address as it's name indicates but an offset.
+   * In 4.3BSD a.out objects this offset is from the start of the "segment" for
+   * which relocation entry is for (text or data).  For Mach-O object files it is
+   * also an offset but from the start of the "section" for which the relocation
+   * entry is for.  See comments in <mach-o/loader.h> about the r_address feild
+   * in images for used with the dynamic linker.
+   *
+   * In 4.3BSD a.out objects if r_extern is zero then r_symbolnum is an ordinal
+   * for the segment the symbol being relocated is in.  These ordinals are the
+   * symbol types N_TEXT, N_DATA, N_BSS or N_ABS.  In Mach-O object files these
+   * ordinals refer to the sections in the object file in the order their section
+   * structures appear in the headers of the object file they are in.  The first
+   * section has the ordinal 1, the second 2, and so on.  This means that the
+   * same ordinal in two different object files could refer to two different
+   * sections.  And further could have still different ordinals when combined
+   * by the link-editor.  The value R_ABS is used for relocation entries for
+   * absolute symbols which need no further relocation.
+    }
+  {
+   * For RISC machines some of the references are split across two instructions
+   * and the instruction does not contain the complete value of the reference.
+   * In these cases a second, or paired relocation entry, follows each of these
+   * relocation entries, using a PAIR r_type, which contains the other part of the
+   * reference not contained in the instruction.  This other part is stored in the
+   * pair's r_address field.  The exact number of bits of the other part of the
+   * reference store in the r_address field is dependent on the particular
+   * relocation type for the particular architecture.
+    }
+  {
+   * To make scattered loading by the link editor work correctly "local"
+   * relocation entries can't be used when the item to be relocated is the value
+   * of a symbol plus an offset (where the resulting expresion is outside the
+   * block the link editor is moving, a blocks are divided at symbol addresses).
+   * In this case. where the item is a symbol value plus offset, the link editor
+   * needs to know more than just the section the symbol was defined.  What is
+   * needed is the actual value of the symbol without the offset so it can do the
+   * relocation correctly based on where the value of the symbol got relocated to
+   * not the value of the expression (with the offset added to the symbol value).
+   * So for the NeXT 2.0 release no "local" relocation entries are ever used when
+   * there is a non-zero offset added to a symbol.  The "external" and "local"
+   * relocation entries remain unchanged.
+   *
+   * The implemention is quite messy given the compatibility with the existing
+   * relocation entry format.  The ASSUMPTION is that a section will never be
+   * bigger than 2**24 - 1 (0x00ffffff or 16,777,215) bytes.  This assumption
+   * allows the r_address (which is really an offset) to fit in 24 bits and high
+   * bit of the r_address field in the relocation_info structure to indicate
+   * it is really a scattered_relocation_info structure.  Since these are only
+   * used in places where "local" relocation entries are used and not where
+   * "external" relocation entries are used the r_extern field has been removed.
+   *
+   * For scattered loading to work on a RISC machine where some of the references
+   * are split across two instructions the link editor needs to be assured that
+   * each reference has a unique 32 bit reference (that more than one reference is
+   * NOT sharing the same high 16 bits for example) so it move each referenced
+   * item independent of each other.  Some compilers guarantees this but the
+   * compilers don't so scattered loading can be done on those that do guarantee
+   * this.
+    }
+
+  {
+   * The reason for the ifdef's of __BIG_ENDIAN__ and __LITTLE_ENDIAN__ are that
+   * when stattered relocation entries were added the mistake of using a mask
+   * against a structure that is made up of bit fields was used.  To make this
+   * design work this structure must be laid out in memory the same way so the
+   * mask can be applied can check the same bit each time (r_scattered).
+    }
+
+
+type
+  scattered_relocation_info = record
+    {$ifdef ENDIAN_BIG}
+    r_info  : longint;  { r_scattered:1,	/* 1=scattered, 0=non-scattered (see above) */
+                          r_pcrel:1,   	/* was relocated pc relative already */
+                  		    r_length:2, 	/* 0=byte, 1=word, 2=long, 3=quad */
+                  		    r_type:4,   	/* if not 0, machine specific relocation type */
+                          r_address:24;	/* offset in the section to what is being relocated */}
+    r_value : int32_t;  {* the value the item to be relocated is refering to (without any offset added) *}
+    {$else}
+    r_value : int32_t;
+    r_info  : longint; {*	r_address:24,	  /* offset in the section to what is being relocated */
+                      		r_type:4,	      /* if not 0, machine specific relocation type */
+                      		r_length:2,	    /* 0=byte, 1=word, 2=long, 3=quad */
+                      		r_pcrel:1, 	    /* was relocated pc relative already */
+                      		r_scattered:1;	/* 1=scattered, 0=non-scattered (see above) */   *}
+    {$endif}
+  end;
+
+  {
+   * Relocation types used in a generic implementation.  Relocation entries for
+   * normal things use the generic relocation as discribed above and their r_type
+   * is GENERIC_RELOC_VANILLA (a value of zero).
+   *
+   * Another type of generic relocation, GENERIC_RELOC_SECTDIFF, is to support
+   * the difference of two symbols defined in different sections.  That is the
+   * expression "symbol1 - symbol2 + constant" is a relocatable expression when
+   * both symbols are defined in some section.  For this type of relocation the
+   * both relocations entries are scattered relocation entries.  The value of
+   * symbol1 is stored in the first relocation entry's r_value field and the
+   * value of symbol2 is stored in the pair's r_value field.
+   *
+   * A special case for a prebound lazy pointer is needed to beable to set the
+   * value of the lazy pointer back to its non-prebound state.  This is done
+   * using the GENERIC_RELOC_PB_LA_PTR r_type.  This is a scattered relocation
+   * entry where the r_value feild is the value of the lazy pointer not prebound.
+    }
+
+const
+  GENERIC_RELOC_VANILLA        = 0; { generic relocation as discribed above  }
+  GENERIC_RELOC_PAIR           = 1; { Only follows a GENERIC_RELOC_SECTDIFF  }
+  GENERIC_RELOC_SECTDIFF       = 2;
+  GENERIC_RELOC_PB_LA_PTR      = 3; { prebound lazy pointer  }
+  GENERIC_RELOC_LOCAL_SECTDIFF = 4;
+
+{*
+ * Relocations for x86_64 are a bit different than for other architectures in
+ * Mach-O: Scattered relocations are not used.  Almost all relocations produced
+ * by the compiler are external relocations.  An external relocation has the
+ * r_extern bit set to 1 and the r_symbolnum field contains the symbol table
+ * index of the target label.
+ *
+ * When the assembler is generating relocations, if the target label is a local
+ * label (begins with 'L'), then the previous non-local label in the same
+ * section is used as the target of the external relocation.  An addend is used
+ * with the distance from that non-local label to the target label.  Only when
+ * there is no previous non-local label in the section is an internal
+ * relocation used.
+ *
+ * The addend (i.e. the 4 in _foo+4) is encoded in the instruction (Mach-O does
+ * not have RELA relocations).  For PC-relative relocations, the addend is
+ * stored directly in the instruction.  This is different from other Mach-O
+ * architectures, which encode the addend minus the current section offset.
+ *
+ * The relocation types are:
+ *
+ * 	X86_64_RELOC_UNSIGNED	// for absolute addresses
+ * 	X86_64_RELOC_SIGNED		// for signed 32-bit displacement
+ * 	X86_64_RELOC_BRANCH		// a CALL/JMP instruction with 32-bit displacement
+ * 	X86_64_RELOC_GOT_LOAD	// a MOVQ load of a GOT entry
+ * 	X86_64_RELOC_GOT		// other GOT references
+ * 	X86_64_RELOC_SUBTRACTOR	// must be followed by a X86_64_RELOC_UNSIGNED
+ *
+ * The following are sample assembly instructions, followed by the relocation
+ * and section content they generate in an object file:
+ *
+ * 	call _foo
+ * 		r_type=X86_64_RELOC_BRANCH, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo
+ * 		E8 00 00 00 00
+ *
+ * 	call _foo+4
+ * 		r_type=X86_64_RELOC_BRANCH, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo
+ * 		E8 04 00 00 00
+ *
+ * 	movq _foo@GOTPCREL(%rip), %rax
+ * 		r_type=X86_64_RELOC_GOT_LOAD, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo
+ * 		48 8B 05 00 00 00 00
+ *
+ * 	pushq _foo@GOTPCREL(%rip)
+ * 		r_type=X86_64_RELOC_GOT, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo
+ * 		FF 35 00 00 00 00
+ *
+ * 	movl _foo(%rip), %eax
+ * 		r_type=X86_64_RELOC_SIGNED, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo
+ * 		8B 05 00 00 00 00
+ *
+ * 	movl _foo+4(%rip), %eax
+ * 		r_type=X86_64_RELOC_SIGNED, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo
+ * 		8B 05 04 00 00 00
+ *
+ * 	movb  $0x12, _foo(%rip)
+ * 		r_type=X86_64_RELOC_SIGNED, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo
+ * 		C6 05 FF FF FF FF 12
+ *
+ * 	movl  $0x12345678, _foo(%rip)
+ * 		r_type=X86_64_RELOC_SIGNED, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo
+ * 		C7 05 FC FF FF FF 78 56 34 12
+ *
+ * 	.quad _foo
+ * 		r_type=X86_64_RELOC_UNSIGNED, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_foo
+ * 		00 00 00 00 00 00 00 00
+ *
+ * 	.quad _foo+4
+ * 		r_type=X86_64_RELOC_UNSIGNED, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_foo
+ * 		04 00 00 00 00 00 00 00
+ *
+ * 	.quad _foo - _bar
+ * 		r_type=X86_64_RELOC_SUBTRACTOR, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_bar
+ * 		r_type=X86_64_RELOC_UNSIGNED, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_foo
+ * 		00 00 00 00 00 00 00 00
+ *
+ * 	.quad _foo - _bar + 4
+ * 		r_type=X86_64_RELOC_SUBTRACTOR, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_bar
+ * 		r_type=X86_64_RELOC_UNSIGNED, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_foo
+ * 		04 00 00 00 00 00 00 00
+ *
+ * 	.long _foo - _bar
+ * 		r_type=X86_64_RELOC_SUBTRACTOR, r_length=2, r_extern=1, r_pcrel=0, r_symbolnum=_bar
+ * 		r_type=X86_64_RELOC_UNSIGNED, r_length=2, r_extern=1, r_pcrel=0, r_symbolnum=_foo
+ * 		00 00 00 00
+ *
+ * 	lea L1(%rip), %rax
+ * 		r_type=X86_64_RELOC_SIGNED, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_prev
+ * 		48 8d 05 12 00 00 00
+ * 		// assumes _prev is the first non-local label 0x12 bytes before L1
+ *
+ * 	lea L0(%rip), %rax
+ * 		r_type=X86_64_RELOC_SIGNED, r_length=2, r_extern=0, r_pcrel=1, r_symbolnum=3
+ * 		48 8d 05 56 00 00 00
+ * 		// assumes L0 is in third section, has an address of 0x00000056 in .o
+ * 		// file, and there is no previous non-local label
+ *
+ * 	.quad L1
+ * 		r_type=X86_64_RELOC_UNSIGNED, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_prev
+ * 		12 00 00 00 00 00 00 00
+ * 		// assumes _prev is the first non-local label 0x12 bytes before L1
+ *
+ * 	.quad L0
+ * 		r_type=X86_64_RELOC_UNSIGNED, r_length=3, r_extern=0, r_pcrel=0, r_symbolnum=3
+ * 		56 00 00 00 00 00 00 00
+ * 		// assumes L0 is in third section, has an address of 0x00000056 in .o
+ * 		// file, and there is no previous non-local label
+ *
+ * 	.quad _foo - .
+ * 		r_type=X86_64_RELOC_SUBTRACTOR, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_prev
+ * 		r_type=X86_64_RELOC_UNSIGNED, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_foo
+ * 		EE FF FF FF FF FF FF FF
+ * 		// assumes _prev is the first non-local label 0x12 bytes before this
+ * 		// .quad
+ *
+ * 	.quad _foo - L1
+ * 		r_type=X86_64_RELOC_SUBTRACTOR, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_prev
+ * 		r_type=X86_64_RELOC_UNSIGNED, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_foo
+ * 		EE FF FF FF FF FF FF FF
+ * 		// assumes _prev is the first non-local label 0x12 bytes before L1
+ *
+ * 	.quad L1 - _prev
+ * 		// No relocations.  This is an assembly time constant.
+ * 		12 00 00 00 00 00 00 00
+ * 		// assumes _prev is the first non-local label 0x12 bytes before L1
+ *
+ *
+ *
+ * In final linked images, there are only two valid relocation kinds:
+ *
+ *     r_type=X86_64_RELOC_UNSIGNED, r_length=3, r_pcrel=0, r_extern=1, r_symbolnum=sym_index
+ *	This tells dyld to add the address of a symbol to a pointer sized (8-byte)
+ *  piece of data (i.e on disk the 8-byte piece of data contains the addend). The
+ *  r_symbolnum contains the index into the symbol table of the target symbol.
+ *
+ *     r_type=X86_64_RELOC_UNSIGNED, r_length=3, r_pcrel=0, r_extern=0, r_symbolnum=0
+ * This tells dyld to adjust the pointer sized (8-byte) piece of data by the amount
+ * the containing image was loaded from its base address (e.g. slide).
+ *
+ *}
+
+const
+  X86_64_RELOC_UNSIGNED   = 0; // for absolute addresses
+  X86_64_RELOC_SIGNED     = 1; // for signed 32-bit displacement
+  X86_64_RELOC_BRANCH     = 2; // a CALL/JMP instruction with 32-bit displacement
+  X86_64_RELOC_GOT_LOAD   = 3; // a MOVQ load of a GOT entry
+  X86_64_RELOC_GOT        = 4; // other GOT references
+  X86_64_RELOC_SUBTRACTOR = 5; // must be followed by a X86_64_RELOC_UNSIGNED
+  X86_64_RELOC_SIGNED_1   = 6; // for signed 32-bit displacement with a -1 addend
+  X86_64_RELOC_SIGNED_2   = 7; // for signed 32-bit displacement with a -2 addend
+  X86_64_RELOC_SIGNED_4   = 8; // for signed 32-bit displacement with a -4 addend
+
+
+
+
+  {* Relocation types used in the ppc implementation.  Relocation entries for
+   * things other than instructions use the same generic relocation as discribed
+   * above and their r_type is RELOC_VANILLA.  The rest of the relocation types
+   * are for instructions.  Since they are for instructions the r_address field
+   * indicates the 32 bit instruction that the relocation is to be preformed on.
+   * The fields r_pcrel and r_length are ignored for non-RELOC_VANILLA r_types
+   * except for PPC_RELOC_BR14.
+   *
+   * For PPC_RELOC_BR14 if the r_length is the unused value 3, then the branch was
+   * statically predicted setting or clearing the Y-bit based on the sign of the
+   * displacement or the opcode.  If this is the case the static linker must flip
+   * the value of the Y-bit if the sign of the displacement changes for non-branch
+   * always conditions.
+    }
+
+const
+  PPC_RELOC_VANILLA   = 0; { generic relocation as discribed above  }
+  PPC_RELOC_PAIR      = 1; { the second relocation entry of a pair  }
+  PPC_RELOC_BR14      = 2; { 14 bit branch displacement (to a word address)  }
+  PPC_RELOC_BR24      = 3; { 24 bit branch displacement (to a word address)  }
+  PPC_RELOC_HI16      = 4; { a PAIR follows with the low half  }
+  PPC_RELOC_LO16      = 5; { a PAIR follows with the high half  }
+  PPC_RELOC_HA16      = 6; { Same as the RELOC_HI16 except the low 16 bits and the  }
+                      		 { * high 16 bits are added together with the low 16 bits }
+                      		 { * sign extened first.  This means if bit 15 of the low }
+                      		 { * 16 bits is set the high 16 bits stored in the        }
+                      		 { * instruction will be adjusted. }
+  PPC_RELOC_LO14      = 7; { Same as the LO16 except that the low 2 bits are not    }
+                      		 { * stored in the instruction and are always zero.  This }
+                       		 { * is used in double word load/store instructions.      }
+  PPC_RELOC_SECTDIFF  = 8;       { a PAIR follows with subtract symbol value  }
+  PPC_RELOC_PB_LA_PTR = 9;       { prebound lazy pointer  }
+  PPC_RELOC_HI16_SECTDIFF  = 10; { section difference forms of above.  a PAIR  }
+  PPC_RELOC_LO16_SECTDIFF  = 11; { follows these with subtract symbol value  }
+  PPC_RELOC_HA16_SECTDIFF  = 12;
+  PPC_RELOC_JBSR           = 13;
+  PPC_RELOC_LO14_SECTDIFF  = 14;
+  PPC_RELOC_LOCAL_SECTDIFF = 15; { like PPC_RELOC_SECTDIFF, but the symbol referenced was local.   }
+
+  {
+   * Symbolic debugger symbols.  The comments give the conventional use for
+   *
+   * 	.stabs "n_name", n_type, n_sect, n_desc, n_value
+   *
+   * where n_type is the defined constant and not listed in the comment.  Other
+   * fields not listed are zero. n_sect is the section ordinal the entry is
+   * refering to.
+    }
+
+const
+   N_GSYM    = $20; { global symbol: name,,NO_SECT,type,0  }
+   N_FNAME   = $22; { procedure name (f77 kludge): name,,NO_SECT,0,0  }
+   N_FUN     = $24; { procedure: name,,n_sect,linenumber,address  }
+   N_STSYM   = $26; { static symbol: name,,n_sect,type,address  }
+   N_LCSYM   = $28; { .lcomm symbol: name,,n_sect,type,address  }
+   N_BNSYM   = $2e; { begin nsect sym: 0,,n_sect,0,address  }
+   N_OPT     = $3c; { emitted with gcc2_compiled and in gcc source  }
+   N_RSYM    = $40; { register sym: name,,NO_SECT,type,register  }
+   N_SLINE   = $44; { src line: 0,,n_sect,linenumber,address  }
+   N_ENSYM   = $4e; { end nsect sym: 0,,n_sect,0,address  }
+   N_SSYM    = $60; { structure elt: name,,NO_SECT,type,struct_offset  }
+   N_SO      = $64; { source file name: name,,n_sect,0,address  }
+   N_OSO     = $66; { object file name: name,,0,0,st_mtime  }
+   N_LSYM    = $80; { local sym: name,,NO_SECT,type,offset  }
+   N_BINCL   = $82; { include file beginning: name,,NO_SECT,0,sum  }
+   N_SOL     = $84; { #included file name: name,,n_sect,0,address  }
+   N_PARAMS  = $86; { compiler parameters: name,,NO_SECT,0,0  }
+   N_VERSION = $88; { compiler version: name,,NO_SECT,0,0  }
+   N_OLEVEL  = $8A; { compiler -O level: name,,NO_SECT,0,0  }
+   N_PSYM    = $a0; { parameter: name,,NO_SECT,type,offset  }
+   N_EINCL   = $a2; { include file end: name,,NO_SECT,0,0  }
+   N_ENTRY   = $a4; { alternate entry: name,,n_sect,linenumber,address  }
+   N_LBRAC   = $c0; { left bracket: 0,,NO_SECT,nesting level,address  }
+   N_EXCL    = $c2; { deleted include file: name,,NO_SECT,0,sum  }
+   N_RBRAC   = $e0; { right bracket: 0,,NO_SECT,nesting level,address  }
+   N_BCOMM   = $e2; { begin common: name,,NO_SECT,0,0  }
+   N_ECOMM   = $e4; { end common: name,,n_sect,0,0  }
+   N_ECOML   = $e8; { end common (local name): 0,,n_sect,0,address  }
+   N_LENG    = $fe; { second stab entry with length information  }
+   { * for the berkeley pascal compiler, pc(1): }
+   N_PC      = $30; {   global pascal symbol: name,,NO_SECT,subtype,line  }
+
+implementation
+
+end.
+
+
+

+ 1466 - 0
compiler/machoutils.pas

@@ -0,0 +1,1466 @@
+{
+    Copyright (c) 2009-2010 by Dmitry Boyarintsev
+
+    Contains utility routines and types for handling mach-o structure and types.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+
+}
+
+unit machoutils;
+
+interface
+
+{$mode objfpc}{$h+}
+
+uses
+  macho;
+
+  type
+    TRawWriter=class(TObject)
+      public
+        procedure WriteRaw(const data; datasize: Integer); virtual; abstract;
+      end;
+
+    TRawReader=class(TObject)
+      public
+        function ReadRaw(var data; datasize: Integer): Integer; virtual; abstract;
+        function Seek(pos: qword): Boolean; virtual; abstract;
+        function ReadPos: qword; virtual; abstract;
+      end;
+
+    TMachHeader=record
+      cputype     : cpu_type_t;
+      cpusubtype  : cpu_subtype_t;
+      filetype    : longword;
+      ncmds       : longword;
+      sizeofcmds  : longword;
+      flags       : longword;
+    end;
+
+    TSegmentName=string[16];
+    TSectionName=TSegmentName;
+
+    TMachoSegment=record
+      segname    : TSegmentName;
+      vmaddr     : qword;
+      vmsize     : qword;
+      fileoff    : qword;
+      filesize   : qword;
+      maxprot    : vm_prot_t;
+      initprot   : vm_prot_t;
+      nsects     : longword;
+      flags      : longword;
+    end;
+
+    TMachoSection=record
+      sectname  : TSectionName;
+      segname   : TSegmentName;
+      addr      : uint64_t;
+      size      : uint64_t;
+      offset    : uint32_t;
+      align     : uint32_t;
+      reloff    : uint32_t;
+      nreloc    : uint32_t;
+      flags     : uint32_t;
+
+      indirectIndex  : Integer; // reserved1 for LAZY and NON_LAZY pointers
+      stubSize       : Integer; // reserved2 for S_SYMBOL_STUBS
+    end;
+
+    TMachoRoutine=record
+      init_address : uint64_t;    { address of initialization routine  }
+      init_module  : uint64_t;    { index into the module table that  }
+    end;
+
+    { TMachoWriter }
+
+    TMachoWriter=class(TObject)
+      private
+        fwriter : TRawWriter;
+        fown    : Boolean;
+      protected
+      public
+        constructor Create(ARawWriter: TRawWriter; AllowFreeWriter: Boolean);
+        destructor Destroy; override;
+
+        { non platform specific writer }
+        procedure WriteData(const data; dataSize: Integer);
+        procedure WriteUint8(i: uint8_t);
+
+        { endian specific writer }
+        procedure WriteUint16(i: uint16_t); virtual; abstract;
+        procedure WriteUint32(i: uint32_t); virtual; abstract;
+        procedure WriteUint64(i: uint64_t); virtual; abstract;
+
+        { endian and ptr-size specific writer }
+        procedure WritePtr(ofs: QWord); virtual; abstract; // ptr is 32 bit for 32-bit platforms
+
+        { macro utility methods }
+
+        procedure WriteHeader(const hdr: TMachHeader); virtual; abstract;
+        procedure WriteSegmentCmd(const seg: TMachoSegment; cmdSize: LongWord); virtual; abstract;
+        procedure WriteSection(const sec: TMachoSection); virtual; abstract;
+        procedure WriteRoutineCmd(const rt: TMachoRoutine); virtual; abstract;
+        procedure WriteLoadCommand(const cmd: load_command); virtual; abstract; overload;
+        procedure WriteLoadCommand(cmd, cmdsize: Integer); overload;
+        procedure WriteRelocation(const ri: relocation_info); virtual; abstract;
+        procedure WriteScatterReloc(const ri: scattered_relocation_info); virtual; abstract;
+        procedure WriteNList(const list: nlist_64); virtual; abstract;
+      end;
+
+    { TLE32MachoWriter }
+
+    TLE32MachoWriter=class(TMachoWriter)
+      public
+        procedure WriteUint16(i: uint16_t); override;
+        procedure WriteUint32(i: uint32_t); override;
+        procedure WriteUint64(i: uint64_t); override;
+        procedure WritePtr(ofs: QWord); override;
+
+        procedure WriteHeader(const hdr: TMachHeader); override;
+        procedure WriteSegmentCmd(const seg: TMachoSegment; ACmdSize: LongWord); override;
+        procedure WriteSection(const sec: TMachoSection); override;
+        procedure WriteRoutineCmd(const rt: TMachoRoutine); override;
+        procedure WriteLoadCommand(const cmd: load_command); override;
+        procedure WriteRelocation(const ri: relocation_info); override;
+        procedure WriteScatterReloc(const ri: scattered_relocation_info); override;
+        procedure WriteNList(const list: nlist_64); override;
+      end;
+
+    { TLE64MachoWriter }
+
+    TLE64MachoWriter=class(TLE32MachoWriter)
+      public
+        procedure WritePtr(ofs: QWord); override;
+
+        procedure WriteHeader(const hdr: TMachHeader); override;
+        procedure WriteSegmentCmd(const seg: TMachoSegment; acmdSize: LongWord); override;
+        procedure WriteSection(const sec: TMachoSection); override;
+        procedure WriteRoutineCmd(const rt: TMachoRoutine); override;
+        procedure WriteNList(const list: nlist_64); override;
+      end;
+
+    { TBE32MachoWriter }
+
+    TBE32MachoWriter=class(TMachoWriter)
+      public
+        procedure WriteUint16(i: uint16_t); override;
+        procedure WriteUint32(i: uint32_t); override;
+        procedure WriteUint64(i: uint64_t); override;
+        procedure WritePtr(ofs: QWord); override;
+
+        procedure WriteHeader(const hdr: TMachHeader); override;
+        procedure WriteSegmentCmd(const seg: TMachoSegment; acmdSize: LongWord); override;
+        procedure WriteSection(const sec: TMachoSection); override;
+        procedure WriteRoutineCmd(const rt: TMachoRoutine); override;
+        procedure WriteLoadCommand(const cmd: load_command); override;
+        procedure WriteRelocation(const ri: relocation_info); override;
+        procedure WriteScatterReloc(const ri: scattered_relocation_info); override;
+        procedure WriteNList(const list: nlist_64); override;
+      end;
+
+      { TBE64MachoWriter }
+
+    TBE64MachoWriter=class(TBE32MachoWriter)
+      public
+        procedure WritePtr(ofs: QWord); override;
+
+        procedure WriteHeader(const hdr: TMachHeader); override;
+        procedure WriteSegmentCmd(const seg: TMachoSegment; acmdSize: LongWord); override;
+        procedure WriteSection(const sec: TMachoSection); override;
+        procedure WriteRoutineCmd(const rt: TMachoRoutine); override;
+        procedure WriteNList(const list: nlist_64); override;
+      end;
+
+
+    { TLEMachoStructConverter }
+
+    { converter for Little-endian structures to Host }
+    TLEMachoStructConverter = class(TObject)
+      public
+        procedure ConvertMachoHeader(const mh: mach_header; var hdr: TMachHeader); virtual;
+        procedure ConvertMachoHeader64(const mh: mach_header_64; var hdr: TMachHeader); virtual;
+        procedure ConvertLoadCommand(var cmd: load_command); virtual;
+        procedure ConvertSegment(const segcmd: segment_command; var segment: TMachoSegment); virtual;
+        procedure ConvertSegment64(const segcmd: segment_command_64; var segment: TMachoSegment); virtual;
+        procedure ConvertSection(const sec: section; var section: TMachoSection); virtual;
+        procedure ConvertSection64(const sec: section_64; var section: TMachoSection); virtual;
+
+        procedure ConvertUInt16(var v: Word); virtual;
+        procedure ConvertUInt32(var v: LongWord); virtual;
+        procedure ConvertUInt64(var v: qWord); virtual;
+      end;
+
+    { converter for Big-endian structures to Host }
+    TBEMachoStructConverter = class(TLEMachoStructConverter);
+
+    {common}
+    TMachoStructConverter = TLEMachoStructConverter;
+
+    { TMachoReader }
+
+    TMachoReader=class(TObject)
+      private
+        fReader : TRawReader;
+        HdrOfs  : qword;
+        fCnv    : TMachoStructConverter;
+        fHdr    : TMachHeader;
+        is64    : Boolean;
+        cmdofs  : array of qword;
+        cmds    : array of load_command;
+      protected
+        function IntReadStruct: Boolean;
+      public
+        constructor Create(ARawReader: TRawReader; StartOfs: QWord=0);
+        function ReadHeader(var hdr: TMachHeader): Boolean;
+        function ReadCommandID(index: LongWord; var cmd: load_command): Boolean;
+        function GetCmdOfs(index: LongWord): qword;
+
+        function ReadSegmentCommand(cmdindex: LongWord; var segment: TMachoSegment): Boolean;
+        function ReadSection(segindex, secindex: LongWord; var machsection: TMachoSection): Boolean;
+
+        function ReadSymTabCmd(var symcmd: symtab_command): Boolean;
+
+        function ReadUInt32(var v: LongWord): Boolean;
+        function ReadData(var data; dataSize: Integer): Integer;
+
+        {todo: ReadNList - using index of symbol, instead of file offset?}
+        function GetNListSize: Integer;
+        function ReadNList(fileofs: qword; var nsym: nlist_64): Boolean;
+
+        procedure Seek(apos: qword);
+      end;
+
+    const
+      seg_TEXT   : TSegmentName = '__TEXT';
+      seg_DATA   : TSegmentName = '__DATA';
+      seg_OBJC   : TSegmentName = '__OBJC';
+      seg_IMPORT : TSegmentName = '__IMPORT';
+      seg_DWARF  : TSegmentName = '__DWARF';
+
+    function AllocMachoWriter(cputarget: cpu_type_t; ARawWriter: TRawWriter; AllowFreeWriter: Boolean): TMachoWriter;
+
+    function sizeMachHeader(cputarget: cpu_type_t): integer; inline;
+    function sizeSegment(cputarget: cpu_type_t): integer; inline;
+    function sizeSection(cputarget: cpu_type_t): integer; inline;
+    function sizeNList(cputarget: cpu_type_t): integer; inline;
+
+    function AlignAddr(cputarget: cpu_type_t; addr: qword): qword;
+
+    procedure InitSegment(var seg: TMachoSegment);
+
+    function MakeSectionName(const segName, secName: shortstring): shortstring;
+    function GetSegmentSectionName(const objSecName: shortstring; var segName, secName: shortstring): shortstring;
+
+    function GetSectionFlags(const segName, secName: shortstring): LongWord;
+
+    type
+      TRelocInfoLength = (ril_byte = 0, ril_word = 1, ril_long = 2, ril_quad = 3);
+
+    procedure RelocInfo(addr, symnum, reltype: integer; len: TRelocInfoLength; pcrel, extern: Boolean; var info: relocation_info);
+    procedure ScatterRelocInfo(value, addr, reltype: integer; len: TRelocInfoLength; pcrel: Boolean; var info: scattered_relocation_info);
+
+    function GetReserved1(const macho: TMachoSection): integer;
+    function GetReserved2(const macho: TMachoSection): integer;
+
+    function GetStubSize(cputarget: Integer; Pic: Boolean): Integer;
+    function MachoAlign(al: integer): integer;
+
+implementation
+
+  function MachoAlign(al: integer): integer;
+    begin
+      Result:=0;
+      al:=al shr 1;
+      while al>0 do
+        begin
+          inc(Result);
+          al:=al shr 1;
+        end;
+    end;
+
+
+  function AllocConverter(magic: LongWord): TMachoStructConverter;
+    begin
+      {$ifdef ENDIAN_BIG}
+      if magic=MH_MAGIC then
+        Result:=TBEMachoStructConverter.Create
+      else
+        Result:=TLEMachoStructConverter.Create;
+      {$else}
+      if magic=MH_MAGIC then
+        Result:=TLEMachoStructConverter.Create
+      else
+        Result:=TBEMachoStructConverter.Create;
+      {$endif}
+    end;
+
+
+  {result values are used from aggas.pas, see TGNUAssembler.WriteSection }
+  function GetStubSize(cputarget: Integer; Pic: Boolean): Integer;
+    begin
+      case cputarget of
+        CPU_TYPE_I386,  CPU_TYPE_X86_64:
+          Result:=5;
+        CPU_TYPE_POWERPC, CPU_TYPE_POWERPC64:
+          if Pic then
+            Result:=32
+          else
+            Result:=16;
+        CPU_TYPE_ARM:
+          if Pic then
+            Result:=16
+          else
+            Result:=12;
+      else
+        Result:=-1;
+      end;
+    end;
+
+
+  function GetReserved1(const macho: TMachoSection): integer;
+    begin
+      case macho.flags and SECTION_TYPE of
+        S_NON_LAZY_SYMBOL_POINTERS, S_LAZY_SYMBOL_POINTERS:
+          Result:=macho.indirectIndex;
+      else
+        Result:=0;
+      end;
+    end;
+
+
+  function GetReserved2(const macho: TMachoSection): integer;
+    begin
+      case macho.flags and SECTION_TYPE of
+        S_SYMBOL_STUBS:
+          Result:=macho.stubSize
+      else
+        Result:=0;
+      end;
+    end;
+
+
+  procedure RelocInfo(addr, symnum, reltype: integer; len: TRelocInfoLength; pcrel, extern: Boolean; var info: relocation_info);
+    {$ifdef ENDIAN_BIG}
+    const
+      relbit : array [Boolean] of Integer = (0, 1 shl 7);
+      extbit : array [Boolean] of Integer = (0, 1 shl 4);
+      ri_len_mask : array [TRelocInfoLength] of Integer = (0 shl 5, 1 shl 5, 2 shl 5, 3 shl 5);
+    begin
+      info.r_address:=addr;
+      info.r_info:=((symnum and $FFFFFF) shl 8) or // r_symbolnum:24
+                    relbit[pcrel] or               // r_pcrel:1;
+                    ri_len_mask[len] or            // r_length:2;
+                    extbit[extern] or              // r_extern:1;
+                    (reltype and $F);              // r_type:4;
+    end;
+    {$else}
+    const
+      relbit : array [Boolean] of Integer = (0, 1 shl 24);
+      extbit : array [Boolean] of Integer = (0, 1 shl 27);
+      ri_len_mask : array [TRelocInfoLength] of Integer = (0 shl 25, 1 shl 25, 2 shl 25, 3 shl 25);
+    begin
+      info.r_address:=addr;
+      info.r_info:=(symnum and $FFFFFF) or // r_symbolnum:24
+                   relbit[pcrel] or        // r_pcrel:1;
+                   extbit[extern] or       // r_length:2;
+                   ri_len_mask[len] or     // r_extern:1;
+                   (reltype shl 28);       // r_type:4;
+    end;
+    {$endif}
+
+
+const
+    si_len_mask: array [TRelocInfoLength] of Integer = (0 shl 28, 1 shl 28, 2 shl 28, 3 shl 28);
+    si_type_ofs    = 24;
+    si_pcrel_bit   = 1 shl 30;
+    si_scatter_bit = 1 shl 31;
+    si_addr_ofs    = 0;
+
+
+  procedure ScatterRelocInfo(value, addr, reltype: integer; len: TRelocInfoLength; pcrel: Boolean; var info: scattered_relocation_info);
+    const
+      relbit : array [Boolean] of Integer = (0, si_pcrel_bit);
+    begin
+                                                          // big endian
+      info.r_info:=si_scatter_bit or                      // r_scattered:1,	/* 1=scattered, 0=non-scattered (see above) */
+                   relbit[pcrel] or                       // r_pcrel:1,   	/* was relocated pc relative already */
+                   si_len_mask[len] or                    // r_length:2,    /* 0=byte, 1=word, 2=long, 3=quad */
+                   ((reltype and $F) shl si_type_ofs) or  // r_type:4,   	  /* if not 0, machine specific relocation type */
+                   ((addr and $FFFFFF) shl si_addr_ofs);  // r_address:24;	/* offset in the section to what is being relocated */}
+      info.r_value:=value;
+                                                          // little endian
+                                                          // r_address:24,	  /* offset in the section to what is being relocated */
+                                                          // r_type:4,	      /* if not 0, machine specific relocation type */
+                                                          // r_length:2,	    /* 0=byte, 1=word, 2=long, 3=quad */
+                                                          // r_pcrel:1, 	    /* was relocated pc relative already */
+                                                          // r_scattered:1;	/* 1=scattered, 0=non-scattered (see above) */   *}
+    end;
+
+
+  function GetSectionFlags(const segName, secName: shortstring): LongWord;
+    begin
+      Result:=0;
+      if segName = seg_DATA then
+        begin
+          if secName = '__nl_symbol_ptr' then
+            Result:=Result or S_NON_LAZY_SYMBOL_POINTERS
+          else if secName = '__la_symbol_ptr' then
+            Result:=Result or S_LAZY_SYMBOL_POINTERS
+          else if secName = '__common' then
+            Result:=Result or S_ZEROFILL
+        end
+      else if segName = seg_TEXT then
+        begin
+          if (secName = '__text') then
+            Result:=Result or S_ATTR_PURE_INSTRUCTIONS or S_ATTR_SOME_INSTRUCTIONS
+          else if secName = '__textcoal_nt' then
+            Result:=Result or S_ATTR_PURE_INSTRUCTIONS or S_ATTR_SOME_INSTRUCTIONS or S_COALESCED
+          else if secName = '.fpc' then
+            Result:=Result or S_ATTR_NO_DEAD_STRIP
+          else if secName = '__cstring' then
+            Result:=Result or S_CSTRING_LITERALS;
+        end
+      else if (segName = seg_IMPORT) then
+        begin
+          if (secName = '__jump_table') then
+            Result:=Result or S_SYMBOL_STUBS or S_ATTR_SELF_MODIFYING_CODE or S_ATTR_SOME_INSTRUCTIONS
+        end
+      else if (segName=seg_OBJC) then
+        begin
+          Result:=S_ATTR_NO_DEAD_STRIP;
+          if secName='__message_refs' then
+            Result:=Result or S_ATTR_NO_DEAD_STRIP or S_LITERAL_POINTERS
+          else if secName='__cls_refs' then
+            Result:=Result or S_ATTR_NO_DEAD_STRIP or S_LITERAL_POINTERS;
+        end;
+    end;
+
+
+  function MakeSectionName(const segName, secName: shortstring): shortstring;
+    begin
+      if segName = '' then
+        Result:=secName
+      else
+        Result:=segName+' '+secName;
+    end;
+
+
+  function GetSegmentSectionName(const objSecName: shortstring; var segName, secName: shortstring): shortstring;
+    var
+      i : integer;
+    begin
+      i:=Pos(' ', objSecName);
+      if i>0 then
+        begin
+          segName:=copy(objsecName, 1, i-1);
+          secName:=copy(objsecName, i+1, length(objsecName)-i);
+        end
+      else
+        begin
+          segName:='';
+          secName:=objSecName;
+        end;
+      Result:=objSecName;
+    end;
+
+
+  procedure InitSegment(var seg: TMachoSegment);
+    begin
+      FillChar(seg, sizeof(seg), 0);
+      seg.initprot:=VM_PROT_ALL;
+      seg.maxprot:=VM_PROT_ALL;
+    end;
+
+
+  const
+    is64MachHeaderSize : array [Boolean] of Integer = ( sizeof(mach_header),  sizeof(mach_header_64));
+    is64SectionSize : array [Boolean] of Integer = ( sizeof(section),  sizeof(section_64));
+    is64SegmentSize : array [Boolean] of Integer = ( sizeof(segment_command),  sizeof(segment_command_64));
+    is64NListSize : array [Boolean] of Integer = (sizeof(nlist), sizeof(nlist_64));
+
+  function AlignAddr(cputarget: cpu_type_t; addr: qword): qword;
+    var
+      md  : array [Boolean] of integer = (4, 8);
+      p   : PtrUInt;
+    begin
+      p:=addr;
+      p:=align(p, md[cputarget and CPU_ARCH_ABI64 > 0]);
+      Result:=qword(p);
+    end;
+
+
+  function sizeMachHeader(cputarget: cpu_type_t): integer;
+    begin
+      Result:=is64MachHeaderSize[ cputarget and CPU_ARCH_ABI64 > 0];
+    end;
+
+
+  function sizeSegment(cputarget: cpu_type_t): integer;
+    begin
+      Result:=is64SegmentSize[ cputarget and CPU_ARCH_ABI64 > 0];
+    end;
+
+
+  function sizeSection(cputarget: cpu_type_t): integer;
+    begin
+      Result:=is64SectionSize[ cputarget and CPU_ARCH_ABI64 > 0];
+    end;
+
+
+  function sizeNList(cputarget: cpu_type_t): integer; inline;
+    begin
+      Result:=is64NlistSize[ cputarget and CPU_ARCH_ABI64 > 0];
+    end;
+
+
+  function AllocMachoWriter(cputarget: cpu_type_t; ARawWriter: TRawWriter; AllowFreeWriter: Boolean): TMachoWriter;
+    begin
+      case cputarget of
+        CPU_TYPE_I386,
+        CPU_TYPE_ARM: Result:=TLE32MachoWriter.Create(ARawWriter, AllowFreeWriter);
+        CPU_TYPE_X86_64: Result:=TLE64MachoWriter.Create(ARawWriter, AllowFreeWriter);
+        CPU_TYPE_POWERPC:  Result:=TBE32MachoWriter.Create(ARawWriter, AllowFreeWriter);
+        CPU_TYPE_POWERPC64: Result:=TBE64MachoWriter.Create(ARawWriter, AllowFreeWriter);
+      else
+        begin
+          if AllowFreeWriter then
+            ARawWriter.Free;
+          Result:=nil;
+        end;
+      end;
+    end;
+
+
+  { TMachoWriter }
+
+  procedure TMachoWriter.WriteData(const data; dataSize: Integer);
+    begin
+      if not assigned(fwriter) then
+        Exit;
+      fwriter.WriteRaw(data, dataSize);
+    end;
+
+
+  procedure TMachoWriter.WriteUint8(i: uint8_t);
+    begin
+      WriteData(i, sizeof(i));
+    end;
+
+
+  procedure TMachoWriter.WriteLoadCommand(cmd, cmdsize: Integer);
+    var
+      m : load_command;
+    begin
+      m.cmd:=cmd;
+      m.cmdsize:=cmdsize;
+      WriteLoadCommand(m);
+    end;
+
+
+  constructor TMachoWriter.Create(ARawWriter: TRawWriter; AllowFreeWriter: Boolean);
+    begin
+      inherited Create;
+      fwriter:=ARawWriter;
+      fown:=AllowFreeWriter;
+    end;
+
+
+  destructor TMachoWriter.Destroy;
+    begin
+      if fown then
+        fwriter.Free;
+      inherited Destroy;
+    end;
+
+
+  { TLE32MachoWriter }
+
+  procedure TLE32MachoWriter.WriteHeader(const hdr: TMachHeader);
+    var
+      m : mach_header;
+    begin
+      with m do
+        begin
+          magic:=NtoLE(MH_MAGIC);
+          cputype:=NtoLE(hdr.cputype);
+          cpusubtype:=NtoLE(hdr.cpusubtype);
+          filetype:=NtoLE(hdr.filetype);
+          ncmds:=NtoLE(hdr.ncmds);
+          sizeofcmds:=NtoLE(hdr.sizeofcmds);
+          flags:=NtoLE(hdr.flags);
+        end;
+      WriteData(m, sizeof(m));
+    end;
+
+
+  procedure TLE32MachoWriter.WriteSegmentCmd(const seg: TMachoSegment; ACmdSize: LongWord);
+    var
+      m : segment_command;
+    begin
+      with m do
+        begin
+          cmd:=NtoLE(LC_SEGMENT);
+          cmdsize:=NtoLE(ACmdSize);
+          segname:=seg.segname;
+          vmaddr:=NtoLE(uint32_t(seg.vmaddr));
+          vmsize:=NtoLE(uint32_t(seg.vmsize));
+          fileoff:=NtoLE(uint32_t(seg.fileoff));
+          filesize:=NtoLE(uint32_t(seg.filesize));
+          maxprot:=NtoLE(seg.maxprot);
+          initprot:=NtoLE(seg.initprot);
+          nsects:=NtoLE(seg.nsects);
+          flags:=NtoLE(seg.flags);
+        end;
+      WriteData(m, sizeof(m));
+    end;
+
+
+  procedure TLE32MachoWriter.WriteSection(const sec: TMachoSection);
+    var
+      m : section;
+    begin
+      FillChar(m, sizeof(m), 0);
+      with m do
+        begin
+          sectname:=sec.sectname;
+          segname:=sec.segname;
+          addr:=NtoLE(sec.addr);
+          size:=NtoLE(sec.size);
+          offset:=NtoLE(sec.offset);
+          align:=NtoLE(sec.align);
+          reloff:=NtoLE(sec.reloff);
+          nreloc:=NtoLE(sec.nreloc);
+          flags:=NtoLE(sec.flags);
+          reserved1:=NtoLE( GetReserved1(sec));
+          reserved2:=NtoLE( GetReserved2(sec));
+        end;
+      WriteData(m, sizeof(m));
+    end;
+
+
+  procedure TLE32MachoWriter.WriteRoutineCmd(const rt: TMachoRoutine);
+    var
+      m : routines_command;
+    begin
+      FillChar(m, sizeof(m), 0);
+      with m do
+        begin
+          cmd:=NtoLE(LC_ROUTINES);
+          cmdsize:=NtoLE(sizeof(m));
+          init_address:=NtoLE(rt.init_address);
+          init_module:=NtoLE(rt.init_module);
+        end;
+      WriteData(m, sizeof(m));
+    end;
+
+
+  procedure TLE32MachoWriter.WriteLoadCommand(const cmd: load_command);
+    var
+      m : load_command;
+    begin
+      m.cmd:=NtoLE(cmd.cmd);
+      m.cmdsize:=NtoLE(cmd.cmdsize);
+      WriteData(m, sizeof(m));
+    end;
+
+
+  procedure TLE32MachoWriter.WriteRelocation(const ri: relocation_info);
+    var
+      m : relocation_info;
+    begin
+      m.r_address:=NtoLE(ri.r_address);
+      m.r_info:=NtoLE(ri.r_info);
+      WriteData(m, sizeof(m));
+    end;
+
+
+  procedure TLE32MachoWriter.WriteScatterReloc(const ri: scattered_relocation_info);
+    var
+      m : LongWord;
+    begin
+      m:=LongWord(ri.r_info);
+      WriteUint32(NtoLE(m));
+
+      m:=LongWord(ri.r_value);
+      WriteUint32(NtoLE(m));
+    end;
+
+
+  procedure TLE32MachoWriter.WriteNList(const list: nlist_64);
+    var
+      m : nlist;
+    begin
+      m.n_un.n_strx:=NtoLe(list.n_un.n_strx);
+      m.n_type:=NtoLe(list.n_type);
+      m.n_sect:=NtoLe(list.n_sect);
+      m.n_desc:=NtoLe(list.n_desc);
+      m.n_value:=NtoLe(list.n_value);
+      WriteData(m, sizeof(m));
+    end;
+
+
+  procedure TLE32MachoWriter.WriteUint16(i: uint16_t);
+    var
+      m: uint16_t;
+    begin
+      m:=NtoLE(i);
+      WriteData(m, sizeof(m));
+    end;
+
+
+  procedure TLE32MachoWriter.WriteUint32(i: uint32_t);
+    var
+      m: uint32_t;
+    begin
+      m:=NtoLE(i);
+      WriteData(m, sizeof(m));
+    end;
+
+
+  procedure TLE32MachoWriter.WriteUint64(i: uint64_t);
+    var
+      m: uint64_t;
+    begin
+      m:=NtoLE(i);
+      WriteData(m, sizeof(m));
+    end;
+
+
+  procedure TLE32MachoWriter.WritePtr(ofs: QWord);
+    var
+      m: uint32_t;
+    begin
+      m:=NtoLE(ofs);
+      WriteData(m, sizeof(m));
+    end;
+
+
+  { TLE64MachoWriter }
+
+  procedure TLE64MachoWriter.WritePtr(ofs: QWord);
+    var
+      m : uint64_t;
+    begin
+      m:=NtoLE(ofs);
+      Writedata(m, sizeof(m));
+    end;
+
+
+  procedure TLE64MachoWriter.WriteHeader(const hdr: TMachHeader);
+    var
+      m : mach_header_64;
+    begin
+      with m do
+        begin
+          magic:=NtoLE(MH_MAGIC_64);
+          cputype:=NtoLE(hdr.cputype);
+          cpusubtype:=NtoLE(hdr.cpusubtype);
+          filetype:=NtoLE(hdr.filetype);
+          ncmds:=NtoLE(hdr.ncmds);
+          sizeofcmds:=NtoLE(hdr.sizeofcmds);
+          flags:=NtoLE(hdr.flags);
+          reserved:=0;
+        end;
+      WriteData(m, sizeof(m));
+    end;
+
+
+  procedure TLE64MachoWriter.WriteSegmentCmd(const seg: TMachoSegment; acmdSize: LongWord);
+    var
+      m : segment_command_64;
+    begin
+      with m do
+        begin
+          cmd:=NtoLE(LC_SEGMENT_64);
+          cmdsize:=NtoLE(acmdSize);
+          segname:=seg.segname;
+          vmaddr:=NtoLE(seg.vmaddr);
+          vmsize:=NtoLE(seg.vmsize);
+          fileoff:=NtoLE(seg.fileoff);
+          filesize:=NtoLE(seg.filesize);
+          maxprot:=NtoLE(seg.maxprot);
+          initprot:=NtoLE(seg.initprot);
+          nsects:=NtoLE(seg.nsects);
+          flags:=NtoLE(seg.flags);
+        end;
+      WriteData(m, sizeof(m));
+    end;
+
+
+  procedure TLE64MachoWriter.WriteSection(const sec: TMachoSection);
+    var
+      m : section_64;
+    begin
+      FillChar(m, sizeof(m), 0);
+      with m do
+        begin
+          sectname:=sec.sectname;
+          segname:=sec.segname;
+          addr:=NtoLE(sec.addr);
+          size:=NtoLE(sec.size);
+          offset:=NtoLE(sec.offset);
+          align:=NtoLE(sec.align);
+          reloff:=NtoLE(sec.reloff);
+          nreloc:=NtoLE(sec.nreloc);
+          flags:=NtoLE(sec.flags);
+          reserved1:=NtoLE( GetReserved1(sec));
+          reserved2:=NtoLE( GetReserved2(sec));
+        end;
+      WriteData(m, sizeof(m));
+    end;
+
+
+  procedure TLE64MachoWriter.WriteRoutineCmd(const rt: TMachoRoutine);
+    var
+      m : routines_command_64;
+    begin
+      FillChar(m, sizeof(m), 0);
+      with m do
+        begin
+          cmd:=NtoLE(LC_ROUTINES);
+          cmdsize:=NtoLE(sizeof(m));
+          init_address:=NtoLE(rt.init_address);
+          init_module:=NtoLE(rt.init_module);
+        end;
+      WriteData(m, sizeof(m));
+    end;
+
+
+  procedure TLE64MachoWriter.WriteNList(const list: nlist_64);
+    var
+      m : nlist_64;
+    begin
+      m.n_un.n_strx:=NtoLe(list.n_un.n_strx);
+      m.n_type:=NtoLe(list.n_type);
+      m.n_sect:=NtoLe(list.n_sect);
+      m.n_desc:=NtoLe(list.n_desc);
+      m.n_value:=NtoLe(list.n_value);
+      WriteData(m, sizeof(m));
+    end;
+
+
+  { TBE32MachoWriter }
+
+  procedure TBE32MachoWriter.WriteHeader(const hdr: TMachHeader);
+    var
+      m : mach_header;
+    begin
+      with m do
+        begin
+          magic:=NtoBE(MH_MAGIC);
+          cputype:=NtoBE(hdr.cputype);
+          cpusubtype:=NtoBE(hdr.cpusubtype);
+          filetype:=NtoBE(hdr.filetype);
+          ncmds:=NtoBE(hdr.ncmds);
+          sizeofcmds:=NtoBE(hdr.sizeofcmds);
+          flags:=NtoBE(hdr.flags);
+        end;
+      WriteData(m, sizeof(m));
+    end;
+
+
+  procedure TBE32MachoWriter.WriteSegmentCmd(const seg: TMachoSegment; acmdSize: LongWord);
+    var
+      m : segment_command;
+    begin
+      with m do
+        begin
+          cmd:=NtoBE(LC_SEGMENT);
+          cmdsize:=NtoBE(acmdSize);
+          segname:=seg.segname;
+          vmaddr:=NtoBE(uint32_t(seg.vmaddr));
+          vmsize:=NtoBE(uint32_t(seg.vmsize));
+          fileoff:=NtoBE(uint32_t(seg.fileoff));
+          filesize:=NtoBE(uint32_t(seg.filesize));
+          maxprot:=NtoBE(seg.maxprot);
+          initprot:=NtoBE(seg.initprot);
+          nsects:=NtoBE(seg.nsects);
+          flags:=NtoBE(seg.flags);
+        end;
+      WriteData(m, sizeof(m));
+    end;
+
+
+  procedure TBE32MachoWriter.WriteSection(const sec: TMachoSection);
+    var
+      m : section;
+    begin
+      FillChar(m, sizeof(m), 0);
+      with m do
+        begin
+          sectname:=sec.sectname;
+          segname:=sec.segname;
+          addr:=NtoBE(sec.addr);
+          size:=NtoBE(sec.size);
+          offset:=NtoBE(sec.offset);
+          align:=NtoBE(sec.align);
+          reloff:=NtoBE(sec.reloff);
+          nreloc:=NtoBE(sec.nreloc);
+          flags:=NtoBE(sec.flags);
+          reserved1:=NtoBE( GetReserved1(sec));
+          reserved2:=NtoBE( GetReserved2(sec));
+        end;
+      WriteData(m, sizeof(m));
+    end;
+
+
+  procedure TBE32MachoWriter.WriteRoutineCmd(const rt: TMachoRoutine);
+    var
+      m : routines_command;
+    begin
+      FillChar(m, sizeof(m), 0);
+      with m do
+        begin
+          cmd:=NtoBE(LC_ROUTINES);
+          cmdsize:=NtoBE(sizeof(m));
+          init_address:=NtoBE(rt.init_address);
+          init_module:=NtoBE(rt.init_module);
+        end;
+      WriteData(m, sizeof(m));
+    end;
+
+
+  procedure TBE32MachoWriter.WriteLoadCommand(const cmd: load_command);
+    var
+      m : load_command;
+    begin
+      m.cmd:=NtoBE(cmd.cmd);
+      m.cmdsize:=NtoBE(cmd.cmdsize);
+      WriteData(m, sizeof(m));
+    end;
+
+
+  procedure TBE32MachoWriter.WriteRelocation(const ri: relocation_info);
+    var
+      m : relocation_info;
+    begin
+      m.r_address:=NtoBE(ri.r_address);
+      m.r_info:=NtoBE(ri.r_info);
+      WriteData(m, sizeof(m));
+    end;
+
+
+  procedure TBE32MachoWriter.WriteScatterReloc(const ri: scattered_relocation_info);
+    var
+      m : LongWord;
+    begin
+      m:=LongWord(ri.r_info);
+      WriteUint32(NtoBE(m));
+
+      m:=LongWord(ri.r_value);
+      WriteUint32(NtoBE(m));
+    end;
+
+
+  procedure TBE32MachoWriter.WriteNList(const list: nlist_64);
+    var
+      m : nlist;
+    begin
+      m.n_un.n_strx:=NtoBe(list.n_un.n_strx);
+      m.n_type:=NtoBe(list.n_type);
+      m.n_sect:=NtoBe(list.n_sect);
+      m.n_desc:=NtoBe(list.n_desc);
+      m.n_value:=NtoBe(list.n_value);
+      WriteData(m, sizeof(m));
+    end;
+
+
+  procedure TBE32MachoWriter.WriteUint16(i: uint16_t);
+    var
+      m: uint16_t;
+    begin
+      m:=NtoBE(i);
+      WriteData(m, sizeof(m));
+    end;
+
+
+  procedure TBE32MachoWriter.WriteUint32(i: uint32_t);
+    var
+      m: uint32_t;
+    begin
+      m:=NtoBE(i);
+      WriteData(m, sizeof(m));
+    end;
+
+
+  procedure TBE32MachoWriter.WriteUint64(i: uint64_t);
+    var
+      m: uint64_t;
+    begin
+      m:=NtoBE(i);
+      WriteData(m, sizeof(m));
+    end;
+
+
+  procedure TBE32MachoWriter.WritePtr(ofs: QWord);
+    var
+      m: uint32_t;
+    begin
+      m:=NtoBE(ofs);
+      WriteData(m, sizeof(m));
+    end;
+
+
+  { TBE64MachoWriter }
+
+  procedure TBE64MachoWriter.WritePtr(ofs: QWord);
+    var
+      m : uint64_t;
+    begin
+      m:=NtoBE(ofs);
+      Writedata(m, sizeof(m));
+    end;
+
+
+  procedure TBE64MachoWriter.WriteHeader(const hdr: TMachHeader);
+    var
+      m : mach_header_64;
+    begin
+      with m do
+        begin
+          magic:=NtoBE(MH_MAGIC_64);
+          cputype:=NtoBE(hdr.cputype);
+          cpusubtype:=NtoBE(hdr.cpusubtype);
+          filetype:=NtoBE(hdr.filetype);
+          ncmds:=NtoBE(hdr.ncmds);
+          sizeofcmds:=NtoBE(hdr.sizeofcmds);
+          flags:=NtoBE(hdr.flags);
+          reserved:=0;
+        end;
+      WriteData(m, sizeof(m));
+    end;
+
+
+  procedure TBE64MachoWriter.WriteSegmentCmd(const seg: TMachoSegment; acmdSize: LongWord);
+    var
+      m : segment_command_64;
+    begin
+      with m do
+        begin
+          cmd:=NtoBE(LC_SEGMENT_64);
+          cmdsize:=NtoBE(acmdSize);
+          segname:=seg.segname;
+          vmaddr:=NtoBE(seg.vmaddr);
+          vmsize:=NtoBE(seg.vmsize);
+          fileoff:=NtoBE(seg.fileoff);
+          filesize:=NtoBE(seg.filesize);
+          maxprot:=NtoBE(seg.maxprot);
+          initprot:=NtoBE(seg.initprot);
+          nsects:=NtoBE(seg.nsects);
+          flags:=NtoBE(seg.flags);
+        end;
+      WriteData(m, sizeof(m));
+    end;
+
+
+  procedure TBE64MachoWriter.WriteSection(const sec: TMachoSection);
+    var
+      m : section_64;
+    begin
+      FillChar(m, sizeof(m), 0);
+      with m do
+        begin
+          sectname:=sec.sectname;
+          segname:=sec.segname;
+          addr:=NtoBE(sec.addr);
+          size:=NtoBE(sec.size);
+          offset:=NtoBE(sec.offset);
+          align:=NtoBE(sec.align);
+          reloff:=NtoBE(sec.reloff);
+          nreloc:=NtoBE(sec.nreloc);
+          flags:=NtoBE(sec.flags);
+          reserved1:=NtoBE( GetReserved1(sec));
+          reserved2:=NtoBE( GetReserved2(sec));
+        end;
+      WriteData(m, sizeof(m));
+    end;
+
+
+  procedure TBE64MachoWriter.WriteRoutineCmd(const rt: TMachoRoutine);
+    var
+      m : routines_command_64;
+    begin
+      FillChar(m, sizeof(m), 0);
+      with m do
+        begin
+          cmd:=NtoBE(LC_ROUTINES);
+          cmdsize:=NtoBE(sizeof(m));
+          init_address:=NtoBE(rt.init_address);
+          init_module:=NtoBE(rt.init_module);
+        end;
+      WriteData(m, sizeof(m));
+    end;
+
+
+  procedure TBE64MachoWriter.WriteNList(const list: nlist_64);
+    var
+      m : nlist_64;
+    begin
+      m.n_un.n_strx:=NtoBe(list.n_un.n_strx);
+      m.n_type:=NtoBe(list.n_type);
+      m.n_sect:=NtoBe(list.n_sect);
+      m.n_desc:=NtoBe(list.n_desc);
+      m.n_value:=NtoBe(list.n_value);
+      WriteData(m, sizeof(m));
+    end;
+
+
+  { TMachoReader }
+
+  constructor TMachoReader.Create(ARawReader: TRawReader; StartOfs: QWord=0);
+    begin
+      inherited Create;
+      fReader:=ARawReader;
+      hdrofs:=StartOfs;
+    end;
+
+
+  function TMachoReader.IntReadStruct: Boolean;
+    var
+      m   : mach_header_64;
+      i   : Integer;
+      p   : qword;
+    begin
+      Result:=false;
+      if not fReader.Seek(hdrofs) then
+        Exit;
+      //todo:
+      fReader.ReadRaw(m, sizeof(mach_header_64));
+      fCnv:=AllocConverter(m.magic);
+      fCnv.ConvertMachoHeader(pmach_header(@m)^, fhdr);
+      is64:=fhdr.cputype and CPU_ARCH_ABI64>0;
+      Result:=true;
+
+      SetLength(cmds, fHdr.ncmds);
+      if fHdr.ncmds>0 then
+        begin
+          if is64 then
+            p:=sizeof(mach_header_64)
+          else
+            p:=sizeof(mach_header);
+
+          SetLength(cmdofs, fHdr.ncmds);
+          for i:=0 to fHdr.ncmds - 1 do
+            begin
+              cmdofs[i]:=p;
+              fReader.Seek(p);
+              fReader.ReadRaw(cmds[i], sizeof(cmds[i]));
+              fCnv.ConvertLoadCommand(cmds[i]);
+              inc(p, cmds[i].cmdsize);
+            end;
+        end;
+    end;
+
+
+  function TMachoReader.ReadHeader(var hdr: TMachHeader): Boolean;
+    begin
+      if not Assigned(fCnv) then
+        Result:=IntReadStruct
+      else
+        Result:=true;
+      hdr:=fhdr;
+    end;
+
+
+  function TMachoReader.ReadCommandID(index: LongWord; var cmd: load_command): Boolean;
+    begin
+      if not Assigned(fCnv) then
+        IntReadStruct;
+      Result:=(index>=0) and (index<fHdr.ncmds);
+      if not Result then
+        Exit;
+      Result:=true;
+      cmd:=cmds[index];
+    end;
+
+
+  function TMachoReader.ReadSegmentCommand(cmdindex: LongWord; var segment: TMachoSegment): Boolean;
+    var
+      seg64 : segment_command_64;
+      seg32 : segment_command;
+    begin
+      if not Assigned(fCnv) then
+        IntReadStruct;
+
+      Result:=(cmdindex>=0) and
+              (cmdindex<fHdr.ncmds) and
+              (cmds[cmdindex].cmd in [LC_SEGMENT, LC_SEGMENT_64]);
+
+      if Result then
+      begin
+        fReader.Seek(cmdofs[cmdindex]);
+        if is64 then
+          begin
+            Result:=fReader.ReadRaw(seg64, sizeof(seg64))=sizeof(seg64);
+            if Result then
+              fCnv.ConvertSegment64(seg64, segment);
+          end
+        else
+          begin
+            Result:=fReader.ReadRaw(seg32, sizeof(seg32))=sizeof(seg32);
+            if Result then
+              fCnv.ConvertSegment(seg32, segment);
+          end;
+      end;
+    end;
+
+
+  function TMachoReader.GetCmdOfs(index: LongWord): qword;
+    begin
+      if not Assigned(fCnv) then
+        IntReadStruct;
+
+      if (index<0) or
+         (index>=longword(length(cmdofs))) then
+        Result:=0
+      else
+        Result:=cmdofs[index];
+    end;
+
+
+  function TMachoReader.ReadSection(segindex, secindex: LongWord; var machsection: TMachoSection): Boolean;
+    var
+      ofs       : qword;
+      is64bit   : Boolean;
+      buf       : array [0..sizeof(section_64)-1] of byte;
+    const
+      sectsize : array[Boolean] of LongWord = ( sizeof(macho.section), sizeof(macho.section_64));
+      segsize  : array[Boolean] of LongWord = ( sizeof(macho.segment_command), sizeof(macho.segment_command_64));
+    begin
+      if not Assigned(fCnv) then
+        IntReadStruct;
+      Result:=(secindex>=0) and (segindex>=0) and (segindex<fHdr.ncmds) and (cmds[segindex].cmd in [LC_SEGMENT, LC_SEGMENT_64]);
+      if not Result then
+        Exit;
+
+      is64bit:=cmds[segindex].cmd=LC_SEGMENT_64;
+      Result:=secindex<(cmds[segindex].cmdsize-segsize[is64bit]) div sectsize[is64bit];
+      if not Result then
+        Exit;
+
+      ofs:=cmdofs[segindex]+segsize[is64bit]+sectsize[is64]*secindex;
+      fReader.Seek(ofs);
+      fReader.ReadRaw(buf, segsize[is64bit]);
+      if is64bit then
+        fCnv.ConvertSection64( psection_64(@buf)^, machsection)
+      else
+        fCnv.ConvertSection( psection(@buf)^, machsection);
+    end;
+
+
+  function TMachoReader.ReadUInt32(var v: LongWord): Boolean;
+    begin
+      if not Assigned(fCnv) then
+        IntReadStruct;
+      Result:=Assigned(fCnv) and (fReader.ReadRaw(v, sizeof(v))=sizeof(v));
+      if Result then
+        fCnv.ConvertUint32(v);
+    end;
+
+
+  function TMachoReader.ReadData(var data; dataSize: Integer): Integer;
+    begin
+      Result:=fReader.ReadRaw(data, dataSize);
+    end;
+
+
+  function TMachoReader.GetNListSize: Integer;
+    begin
+      if is64 then
+        Result:=sizeof(nlist_64)
+      else
+        Result:=sizeof(nlist);
+    end;
+
+
+  function TMachoReader.ReadNList(fileofs: qword; var nsym: nlist_64): Boolean;
+    var
+      n32 : nlist;
+    begin
+      fReader.Seek(fileofs);
+      if is64 then
+        Result:=fReader.ReadRaw(nsym, sizeof(nlist_64))=sizeof(nlist_64)
+      else
+        begin
+          Result:=fReader.ReadRaw(n32, sizeof(nlist))=sizeof(nlist);
+          nsym.n_un.n_strx:=n32.n_un.n_strx;
+          nsym.n_desc:=n32.n_desc;
+          nsym.n_sect:=n32.n_sect;
+          nsym.n_type:=n32.n_type;
+          nsym.n_value:=n32.n_value;
+        end;
+      fCnv.ConvertUInt32(nsym.n_un.n_strx);
+      fCnv.ConvertUInt16(nsym.n_desc);
+      fCnv.ConvertUInt64(nsym.n_value);
+    end;
+
+
+  function TMachoReader.ReadSymTabCmd(var symcmd: symtab_command): Boolean;
+    var
+      i   : Integer;
+      p   : qword;
+    begin
+      if not Assigned(fCnv) then
+        IntReadStruct;
+
+      for i:=0 to length(cmds)-1 do
+        if cmds[i].cmd=LC_SYMTAB then
+          begin
+            p:=fReader.ReadPos;
+            fReader.Seek(cmdofs[i]);
+            fReader.ReadRaw(symcmd, sizeof(symcmd));
+            fCnv.ConvertUInt32(symcmd.cmd);
+            fCnv.ConvertUInt32(symcmd.cmdsize);
+            fCnv.ConvertUInt32(symcmd.symoff);
+            fCnv.ConvertUInt32(symcmd.nsyms);
+            fCnv.ConvertUInt32(symcmd.stroff);
+            fCnv.ConvertUInt32(symcmd.strsize);
+            fReader.Seek(p);
+            Result:=true;
+            Exit;
+          end;
+      Result:=false;
+    end;
+
+
+  procedure TMachoReader.Seek(apos: qword);
+    begin
+      fReader.Seek(apos);
+    end;
+
+
+  { TLEMachoStructConverter }
+
+  procedure TLEMachoStructConverter.ConvertMachoHeader(const mh: mach_header; var hdr: TMachHeader);
+    begin
+      hdr.cputype:=LEToN(mh.cputype);
+      hdr.cpusubtype:=LEtoN(mh.cpusubtype);
+      hdr.filetype:=LEToN(mh.filetype);
+      hdr.ncmds:=LEToN(mh.ncmds);
+      hdr.sizeofcmds:=LEToN(mh.ncmds);
+      hdr.flags:=LEToN(mh.flags);
+    end;
+
+
+  procedure TLEMachoStructConverter.ConvertMachoHeader64(const mh: mach_header_64; var hdr: TMachHeader);
+    begin
+      hdr.cputype:=LEToN(mh.cputype);
+      hdr.cpusubtype:=LEtoN(mh.cpusubtype);
+      hdr.filetype:=LEToN(mh.filetype);
+      hdr.ncmds:=LEToN(mh.ncmds);
+      hdr.sizeofcmds:=LEToN(mh.ncmds);
+      hdr.flags:=LEToN(mh.flags);
+    end;
+
+
+  procedure TLEMachoStructConverter.ConvertLoadCommand(var cmd: load_command);
+    begin
+      cmd.cmd:=LEToN(cmd.cmd);
+      cmd.cmdsize:=LEToN(cmd.cmdsize);
+    end;
+
+
+  procedure TLEMachoStructConverter.ConvertSegment(const segcmd: segment_command; var segment: TMachoSegment);
+    begin
+      FillChar(segment, sizeof(segment), 0);
+      segment.segname:=segcmd.segname;
+      segment.vmaddr:=LEToN(segcmd.vmaddr);
+      segment.vmsize:=LEToN(segcmd.vmsize);
+      segment.fileoff:=LEToN(segcmd.fileoff);
+      segment.filesize:=LEToN(segcmd.filesize);
+      segment.maxprot:=LEToN(segcmd.maxprot);
+      segment.initprot:=LEToN(segcmd.initprot);
+      writelN('segcmd.nsects = ', segcmd.nsects);
+      segment.nsects:=LEToN(segcmd.nsects);
+      segment.flags:=LEToN(segcmd.flags);
+      //todo: reserved!?
+    end;
+
+
+  procedure TMachoStructConverter.ConvertSegment64(const segcmd: segment_command_64; var segment: TMachoSegment);
+    begin
+      FillChar(segment, sizeof(segment), 0);
+      segment.segname:=segcmd.segname;
+      segment.vmaddr:=LEToN(segcmd.vmaddr);
+      segment.vmsize:=LEToN(segcmd.vmsize);
+      segment.fileoff:=LEToN(segcmd.fileoff);
+      segment.filesize:=LEToN(segcmd.filesize);
+      segment.maxprot:=LEToN(segcmd.maxprot);
+      segment.initprot:=LEToN(segcmd.initprot);
+      segment.nsects:=LEToN(segcmd.nsects);
+      segment.flags:=LEToN(segcmd.flags);
+      //todo: reserved!?
+    end;
+
+
+  procedure TMachoStructConverter.ConvertSection(const sec: section; var section: TMachoSection);
+    begin
+      FillChar(section, sizeof(section), 0);
+      section.sectname:=sec.sectname;
+      section.segname:=sec.segname;
+      section.addr:=LEToN(sec.addr);
+      section.size:=LEToN(sec.size);
+      section.offset:=LEToN(sec.offset);
+      section.align:=LEToN(sec.align);
+      section.reloff:=LEToN(sec.reloff);
+      section.nreloc:=LEToN(sec.nreloc);
+      section.flags:=LEToN(sec.flags);
+      //todo:
+      //section.indirectIndex  : Integer; // reserved1 for LAZY and NON_LAZY pointers
+      //section.stubSize       : Integer; // reserved2 for S_SYMBOL_STUBS
+    end;
+
+
+  procedure TMachoStructConverter.ConvertSection64(const sec: section_64; var section: TMachoSection);
+    begin
+      FillChar(section, sizeof(section), 0);
+      section.sectname:=sec.sectname;
+      section.segname:=sec.segname;
+      section.addr:=LEToN(sec.addr);
+      section.size:=LEToN(sec.size);
+      section.offset:=LEToN(sec.offset);
+      section.align:=LEToN(sec.align);
+      section.reloff:=LEToN(sec.reloff);
+      section.nreloc:=LEToN(sec.nreloc);
+      section.flags:=LEToN(sec.flags);
+      //todo:
+      //section.indirectIndex  : Integer; // reserved1 for LAZY and NON_LAZY pointers
+      //section.stubSize       : Integer; // reserved2 for S_SYMBOL_STUBS
+    end;
+
+
+  procedure TMachoStructConverter.ConvertUInt32(var v: LongWord);
+    begin
+      v:=LEtoN(v);
+    end;
+
+
+  procedure TMachoStructConverter.ConvertUInt64(var v: qword);
+    begin
+      v:=LEtoN(v);
+    end;
+
+
+  procedure TMachoStructConverter.ConvertUInt16(var v: Word);
+    begin
+      v:=LEToN(v);
+    end;
+
+end.
+

+ 1 - 0
compiler/msg/errore.msg

@@ -2872,6 +2872,7 @@ option_help_pages=11025_[
 **1A<x>_Output format:
 **2Adefault_Use default assembler
 3*2Aas_Assemble using GNU AS
+3*2Amacho_Mach-O (Darwin, Intel 32 bit) using internal writer
 3*2Anasmcoff_COFF (Go32v2) file using Nasm
 3*2Anasmelf_ELF32 (Linux) file using Nasm
 3*2Anasmwin32_Win32 object file using Nasm

+ 1 - 1
compiler/msgidx.inc

@@ -840,7 +840,7 @@ const
   option_info=11024;
   option_help_pages=11025;
 
-  MsgTxtSize = 55246;
+  MsgTxtSize = 55308;
 
   MsgIdxMax : array[1..20] of longint=(
     24,87,285,95,71,51,110,22,202,63,

+ 99 - 99
compiler/msgtxt.inc

@@ -1028,274 +1028,274 @@ const msgtxt : array[0..000230,1..240] of char=(
   '**1A<x>_Output format:'#010+
   '**2Adefault_Use default assembler'#010+
   '3*2Aas_Assemble using GNU AS'#010+
-  '3*2Anasmcoff_COFF (Go32v2) file using Nasm'#010+
-  '3*2Anasmelf_ELF32 (Linux) f','ile using Nasm'#010+
+  '3*2Amacho_Mach-O (Darwin, Intel 32 bit) using internal writer'#010+
+  '3*2Anasm','coff_COFF (Go32v2) file using Nasm'#010+
+  '3*2Anasmelf_ELF32 (Linux) file using Nasm'#010+
   '3*2Anasmwin32_Win32 object file using Nasm'#010+
   '3*2Anasmwdosx_Win32/WDOSX object file using Nasm'#010+
   '3*2Awasm_Obj file using Wasm (Watcom)'#010+
   '3*2Anasmobj_Obj file using Nasm'#010+
-  '3*2Amasm_Obj file using Masm (Microsoft)'#010+
-  '3*2Atasm_Obj file usin','g Tasm (Borland)'#010+
+  '3','*2Amasm_Obj file using Masm (Microsoft)'#010+
+  '3*2Atasm_Obj file using Tasm (Borland)'#010+
   '3*2Aelf_ELF (Linux) using internal writer'#010+
   '3*2Acoff_COFF (Go32v2) using internal writer'#010+
   '3*2Apecoff_PE-COFF (Win32) using internal writer'#010+
-  '4*2Aas_Assemble using GNU AS'#010+
+  '4*2Aas_Assemble using GNU',' AS'#010+
   '6*2Aas_Unix o-file using GNU AS'#010+
-  '6*2Agas_GNU Motorola assem','bler'#010+
+  '6*2Agas_GNU Motorola assembler'#010+
   '6*2Amit_MIT Syntax (old GAS)'#010+
   '6*2Amot_Standard Motorola assembler'#010+
   'A*2Aas_Assemble using GNU AS'#010+
   'P*2Aas_Assemble using GNU AS'#010+
   'S*2Aas_Assemble using GNU AS'#010+
-  '**1b_Generate browser info'#010+
+  '**1b_Generate browser',' info'#010+
   '**2bl_Generate local symbol info'#010+
-  '**1B_Build all modules'#010,
+  '**1B_Build all modules'#010+
   '**1C<x>_Code generation options:'#010+
   '**2Ca<x>_Select ABI, see fpc -i for possible values'#010+
   '**2Cb_Generate big-endian code'#010+
   '**2Cc<x>_Set default calling convention to <x>'#010+
-  '**2CD_Create also dynamic library (not supported)'#010+
-  '**2Ce_Compilation with emul','ated floating point opcodes'#010+
+  '**2CD_Create al','so dynamic library (not supported)'#010+
+  '**2Ce_Compilation with emulated floating point opcodes'#010+
   '**2Cf<x>_Select fpu instruction set to use, see fpc -i for possible va'+
   'lues'#010+
   '**2CF<x>_Minimal floating point constant precision (default, 32, 64)'#010+
-  '**2Cg_Generate PIC code'#010+
-  '**2Ch<n>_<n> bytes heap (between 1023 and 67','107840)'#010+
+  '**2Cg_','Generate PIC code'#010+
+  '**2Ch<n>_<n> bytes heap (between 1023 and 67107840)'#010+
   '**2Ci_IO-checking'#010+
   '**2Cn_Omit linking stage'#010+
   '**2Co_Check overflow of integer operations'#010+
   '**2CO_Check for possible overflow of integer operations'#010+
-  '**2Cp<x>_Select instruction set, see fpc -i for possible values'#010+
-  '**2CP<x>=<y>_ packing sett','ings'#010+
+  '**2Cp<x>_Select instruction ','set, see fpc -i for possible values'#010+
+  '**2CP<x>=<y>_ packing settings'#010+
   '**3CPPACKSET=<y>_ <y> set allocation: 0, 1 or DEFAULT or NORMAL, 2, 4 '+
   'and 8'#010+
   '**2Cr_Range checking'#010+
   '**2CR_Verify object method call validity'#010+
-  '**2Cs<n>_Set stack checking size to <n>'#010+
+  '**2Cs<n>_Set stack checking size to',' <n>'#010+
   '**2Ct_Stack checking (for testing only, see manual)'#010+
-  '**2CX','_Create also smartlinked library'#010+
+  '**2CX_Create also smartlinked library'#010+
   '**1d<x>_Defines the symbol <x>'#010+
   '**1D_Generate a DEF file'#010+
   '**2Dd<x>_Set description to <x>'#010+
   '**2Dv<x>_Set DLL version to <x>'#010+
   '*O2Dw_PM application'#010+
-  '**1e<x>_Set path to executable'#010+
+  '**1e','<x>_Set path to executable'#010+
   '**1E_Same as -Cn'#010+
-  '**1fPIC_Same as -C','g'#010+
+  '**1fPIC_Same as -Cg'#010+
   '**1F<x>_Set file names and paths:'#010+
   '**2Fa<x>[,y]_(for a program) load units <x> and [y] before uses is par'+
   'sed'#010+
   '**2Fc<x>_Set input codepage to <x>'#010+
-  '**2FC<x>_Set RC compiler binary name to <x>'#010+
-  '**2Fd_Disable the compiler'#039's internal directory cac','he'#010+
+  '**2FC<x>_Set RC compiler binary n','ame to <x>'#010+
+  '**2Fd_Disable the compiler'#039's internal directory cache'#010+
   '**2FD<x>_Set the directory where to search for compiler utilities'#010+
   '**2Fe<x>_Redirect error output to <x>'#010+
   '**2Ff<x>_Add <x> to framework path (Darwin only)'#010+
-  '**2FE<x>_Set exe/unit output path to <x>'#010+
+  '**2FE<x>_Set exe/unit ','output path to <x>'#010+
   '**2Fi<x>_Add <x> to include path'#010+
-  '**2Fl<x>_A','dd <x> to library path'#010+
+  '**2Fl<x>_Add <x> to library path'#010+
   '**2FL<x>_Use <x> as dynamic linker'#010+
   '**2Fm<x>_Load unicode conversion table from <x>.txt in the compiler di'+
   'r'#010+
   '**2Fo<x>_Add <x> to object path'#010+
-  '**2Fr<x>_Load error message file <x>'#010+
-  '**2FR<x>_Set resource (.res) linker to <x','>'#010+
+  '**2Fr<x>_Load er','ror message file <x>'#010+
+  '**2FR<x>_Set resource (.res) linker to <x>'#010+
   '**2Fu<x>_Add <x> to unit path'#010+
   '**2FU<x>_Set unit output path to <x>, overrides -FE'#010+
   '**2FW<x>_Store generated whole-program optimization feedback in <x>'#010+
-  '**2Fw<x>_Load previously stored whole-program optimization feedback fr'+
-  'om <x>'#010+
-  '*g1g_Genera','te debug information (default format for target)'#010+
+  '**2Fw<x>_Load previously s','tored whole-program optimization feedback '+
+  'from <x>'#010+
+  '*g1g_Generate debug information (default format for target)'#010+
   '*g2gc_Generate checks for pointers'#010+
   '*g2gh_Use heaptrace unit (for memory leak/corruption debugging)'#010+
-  '*g2gl_Use line info unit (show more info with backtraces)'#010+
-  '*g2go<x>_Set debug information opt','ions'#010+
+  '*g2gl_Use line info unit (show',' more info with backtraces)'#010+
+  '*g2go<x>_Set debug information options'#010+
   '*g3godwarfsets_ Enable DWARF '#039'set'#039' type debug information (bre'+
   'aks gdb < 6.5)'#010+
   '*g3gostabsabsincludes_ Store absolute/full include file paths in Stabs'+
   #010+
-  '*g3godwarfmethodclassprefix_ Prefix method names in DWARF with class n'+
-  'ame'#010+
-  '*g2gp_Preserv','e case in stabs symbol names'#010+
+  '*g3godwarfmethodclasspref','ix_ Prefix method names in DWARF with class'+
+  ' name'#010+
+  '*g2gp_Preserve case in stabs symbol names'#010+
   '*g2gs_Generate Stabs debug information'#010+
   '*g2gt_Trash local variables (to detect uninitialized uses)'#010+
   '*g2gv_Generates programs traceable with Valgrind'#010+
-  '*g2gw_Generate DWARFv2 debug information (same as -gw2)'#010+
-  '*g2gw2_G','enerate DWARFv2 debug information'#010+
+  '*g','2gw_Generate DWARFv2 debug information (same as -gw2)'#010+
+  '*g2gw2_Generate DWARFv2 debug information'#010+
   '*g2gw3_Generate DWARFv3 debug information'#010+
   '**1i_Information'#010+
   '**2iD_Return compiler date'#010+
   '**2iV_Return short compiler version'#010+
-  '**2iW_Return full compiler version'#010+
+  '**2iW_Return full comp','iler version'#010+
   '**2iSO_Return compiler OS'#010+
-  '**2iSP_Return compiler ','host processor'#010+
+  '**2iSP_Return compiler host processor'#010+
   '**2iTO_Return target OS'#010+
   '**2iTP_Return target processor'#010+
   '**1I<x>_Add <x> to include path'#010+
   '**1k<x>_Pass <x> to the linker'#010+
   '**1l_Write logo'#010+
-  '**1M<x>_Set language mode to <x>'#010+
+  '**1M<x>_Set language mode to ','<x>'#010+
   '**2Mfpc_Free Pascal dialect (default)'#010+
-  '**2Mobjfpc_FPC mode ','with Object Pascal support'#010+
+  '**2Mobjfpc_FPC mode with Object Pascal support'#010+
   '**2Mdelphi_Delphi 7 compatibility mode'#010+
   '**2Mtp_TP/BP 7.0 compatibility mode'#010+
   '**2Mmacpas_Macintosh Pascal dialects compatibility mode'#010+
-  '**1n_Do not read the default config files'#010+
+  '**1n_Do not read the',' default config files'#010+
   '**1N<x>_Node tree optimizations'#010+
-  '**2Nu_Un','roll loops'#010+
+  '**2Nu_Unroll loops'#010+
   '**1o<x>_Change the name of the executable produced to <x>'#010+
   '**1O<x>_Optimizations:'#010+
   '**2O-_Disable optimizations'#010+
-  '**2O1_Level 1 optimizations (quick and debugger friendly)'#010+
+  '**2O1_Level 1 optimizations (quick and debugger friendly)'#010,
   '**2O2_Level 2 optimizations (-O1 + quick optimizations)'#010+
-  '**2O3_','Level 3 optimizations (-O2 + slow optimizations)'#010+
+  '**2O3_Level 3 optimizations (-O2 + slow optimizations)'#010+
   '**2Oa<x>=<y>_Set alignment'#010+
   '**2Oo[NO]<x>_Enable or disable optimizations, see fpc -i for possible '+
   'values'#010+
-  '**2Op<x>_Set target cpu for optimizing, see fpc -i for possible values'+
-  #010+
-  '**2OW<x>_Generat','e whole-program optimization feedback for optimizati'+
-  'on <x>, see fpc -i for possible values'#010+
+  '**2Op<x>_Set target cpu f','or optimizing, see fpc -i for possible valu'+
+  'es'#010+
+  '**2OW<x>_Generate whole-program optimization feedback for optimization'+
+  ' <x>, see fpc -i for possible values'#010+
   '**2Ow<x>_Perform whole-program optimization <x>, see fpc -i for possib'+
   'le values'#010+
-  '**2Os_Optimize for size rather than speed'#010+
-  '**1pg_Generate profile code',' for gprof (defines FPC_PROFILE)'#010+
+  '**2Os_O','ptimize for size rather than speed'#010+
+  '**1pg_Generate profile code for gprof (defines FPC_PROFILE)'#010+
   '**1R<x>_Assembler reading style:'#010+
   '**2Rdefault_Use default assembler for target'#010+
   '3*2Ratt_Read AT&T style assembler'#010+
-  '3*2Rintel_Read Intel style assembler'#010+
+  '3*2Rintel_Read Intel style assemb','ler'#010+
   '6*2RMOT_Read motorola style assembler'#010+
-  '**1S<x>_Syntax optio','ns:'#010+
+  '**1S<x>_Syntax options:'#010+
   '**2S2_Same as -Mobjfpc'#010+
   '**2Sc_Support operators like C (*=,+=,/= and -=)'#010+
   '**2Sa_Turn on assertions'#010+
   '**2Sd_Same as -Mdelphi'#010+
-  '**2Se<x>_Error options. <x> is a combination of the following:'#010+
-  '**3*_<n> : Compiler halts after the <n> errors (defau','lt is 1)'#010+
+  '**2Se<x>_Error options. <x> is a combination of the fo','llowing:'#010+
+  '**3*_<n> : Compiler halts after the <n> errors (default is 1)'#010+
   '**3*_w : Compiler also halts after warnings'#010+
   '**3*_n : Compiler also halts after notes'#010+
   '**3*_h : Compiler also halts after hints'#010+
-  '**2Sg_Enable LABEL and GOTO (default in -Mtp and -Mdelphi)'#010+
-  '**2Sh_Use ansistrings by default instead of sh','ortstrings'#010+
+  '**2Sg_Enable LABEL and GOTO (default in -Mt','p and -Mdelphi)'#010+
+  '**2Sh_Use ansistrings by default instead of shortstrings'#010+
   '**2Si_Turn on inlining of procedures/functions declared as "inline"'#010+
   '**2Sk_Load fpcylix unit'#010+
   '**2SI<x>_Set interface style to <x>'#010+
-  '**3SIcom_COM compatible interface (default)'#010+
+  '**3SIcom_COM compatible interface (defa','ult)'#010+
   '**3SIcorba_CORBA compatible interface'#010+
-  '**2Sm_Support macro','s like C (global)'#010+
+  '**2Sm_Support macros like C (global)'#010+
   '**2So_Same as -Mtp'#010+
   '**2Ss_Constructor name must be init (destructor must be done)'#010+
   '**2Sx_Enable exception keywords (default in Delphi/ObjFPC modes)'#010+
-  '**1s_Do not call assembler and linker'#010+
-  '**2sh_Generate script to link on host'#010,
+  '**1s_Do not ca','ll assembler and linker'#010+
+  '**2sh_Generate script to link on host'#010+
   '**2st_Generate script to link on target'#010+
   '**2sr_Skip register allocation phase (use with -alr)'#010+
   '**1T<x>_Target operating system:'#010+
   '3*2Temx_OS/2 via EMX (including EMX/RSX extender)'#010+
-  '3*2Tfreebsd_FreeBSD'#010+
-  '3*2Tgo32v2_Version 2 of DJ Delorie DOS exten','der'#010+
+  '3*','2Tfreebsd_FreeBSD'#010+
+  '3*2Tgo32v2_Version 2 of DJ Delorie DOS extender'#010+
   '3*2Tlinux_Linux'#010+
   '3*2Tnetbsd_NetBSD'#010+
   '3*2Tnetware_Novell Netware Module (clib)'#010+
   '3*2Tnetwlibc_Novell Netware Module (libc)'#010+
   '3*2Topenbsd_OpenBSD'#010+
   '3*2Tos2_OS/2 / eComStation'#010+
-  '3*2Tsunos_SunOS/Solaris'#010+
+  '3*2Tsunos_','SunOS/Solaris'#010+
   '3*2Tsymbian_Symbian OS'#010+
-  '3*2Twatcom_Watcom compati','ble DOS extender'#010+
+  '3*2Twatcom_Watcom compatible DOS extender'#010+
   '3*2Twdosx_WDOSX DOS extender'#010+
   '3*2Twin32_Windows 32 Bit'#010+
   '3*2Twince_Windows CE'#010+
   '4*2Tlinux_Linux'#010+
   '6*2Tamiga_Commodore Amiga'#010+
   '6*2Tatari_Atari ST/STe/TT'#010+
-  '6*2Tlinux_Linux/m68k'#010+
+  '6*2Tlinux_Linux/m6','8k'#010+
   '6*2Tmacos_Macintosh m68k (not supported)'#010+
-  '6*2Tpalmos_PalmOS'#010,
+  '6*2Tpalmos_PalmOS'#010+
   'A*2Tlinux_Linux'#010+
   'A*2Twince_Windows CE'#010+
   'P*2Tamiga_AmigaOS on PowerPC'#010+
   'P*2Tdarwin_Darwin and Mac OS X on PowerPC'#010+
   'P*2Tlinux_Linux on PowerPC'#010+
   'P*2Tmacos_Mac OS (classic) on PowerPC'#010+
-  'P*2Tmorphos_MorphOS'#010+
+  'P*2Tm','orphos_MorphOS'#010+
   'S*2Tlinux_Linux'#010+
-  '**1u<x>_Undefines the symbol <x','>'#010+
+  '**1u<x>_Undefines the symbol <x>'#010+
   '**1U_Unit options:'#010+
   '**2Un_Do not check where the unit name matches the file name'#010+
   '**2Ur_Generate release unit files (never automatically recompiled)'#010+
   '**2Us_Compile a system unit'#010+
-  '**1v<x>_Be verbose. <x> is a combination of the following lette','rs:'#010+
+  '*','*1v<x>_Be verbose. <x> is a combination of the following letters:'#010+
   '**2*_e : Show errors (default)       0 : Show nothing (except errors)'#010+
   '**2*_w : Show warnings               u : Show unit info'#010+
-  '**2*_n : Show notes                  t : Show tried/used files'#010+
-  '**2*_h : Show hints                  c : Show c','onditionals'#010+
+  '**2*_n : Show notes                  t : Show tr','ied/used files'#010+
+  '**2*_h : Show hints                  c : Show conditionals'#010+
   '**2*_i : Show general info           d : Show debug info'#010+
   '**2*_l : Show linenumbers            r : Rhide/GCC compatibility mode'#010+
-  '**2*_s : Show time stamps            q : Show message numbers'#010+
-  '**2*_a : Show everything             x ',': Executable info (Win32 only'+
-  ')'#010+
+  '**2*_s : Show time stamps            q ',': Show message numbers'#010+
+  '**2*_a : Show everything             x : Executable info (Win32 only)'#010+
   '**2*_b : Write file names messages   p : Write tree.log with parse tre'+
   'e'#010+
   '**2*_    with full path              v : Write fpcdebug.txt with'#010+
-  '**2*_                                    lots of debugging info'#010+
-  '**2*_m<x','>,<y> : Don'#039't show messages numbered <x> and <y>'#010+
+  '**2*_     ','                               lots of debugging info'#010+
+  '**2*_m<x>,<y> : Don'#039't show messages numbered <x> and <y>'#010+
   '3*1W<x>_Target-specific options (targets)'#010+
   'A*1W<x>_Target-specific options (targets)'#010+
   'P*1W<x>_Target-specific options (targets)'#010+
-  'p*1W<x>_Target-specific options (targets)'#010+
-  '3*2Wb_Create a bundle i','nstead of a library (Darwin)'#010+
+  'p*1','W<x>_Target-specific options (targets)'#010+
+  '3*2Wb_Create a bundle instead of a library (Darwin)'#010+
   'P*2Wb_Create a bundle instead of a library (Darwin)'#010+
   'p*2Wb_Create a bundle instead of a library (Darwin)'#010+
   '3*2WB_Create a relocatable image (Windows)'#010+
-  'A*2WB_Create a relocatable image (Windows, Symbian)'#010+
-  '3*2WC_Specif','y console type application (EMX, OS/2, Windows)'#010+
+  'A*','2WB_Create a relocatable image (Windows, Symbian)'#010+
+  '3*2WC_Specify console type application (EMX, OS/2, Windows)'#010+
   'A*2WC_Specify console type application (Windows)'#010+
   'P*2WC_Specify console type application (Classic Mac OS)'#010+
-  '3*2WD_Use DEFFILE to export functions of DLL or EXE (Windows)'#010+
-  'A*2WD_Use DEFFILE to expo','rt functions of DLL or EXE (Windows)'#010+
+  '3*2WD_Use DEFFILE to expo','rt functions of DLL or EXE (Windows)'#010+
+  'A*2WD_Use DEFFILE to export functions of DLL or EXE (Windows)'#010+
   '3*2We_Use external resources (Darwin)'#010+
   'P*2We_Use external resources (Darwin)'#010+
   'p*2We_Use external resources (Darwin)'#010+
-  '3*2WF_Specify full-screen type application (EMX, OS/2)'#010+
-  '3*2WG_Specify graphic type applica','tion (EMX, OS/2, Windows)'#010+
+  '3*2WF_Specify full-screen t','ype application (EMX, OS/2)'#010+
+  '3*2WG_Specify graphic type application (EMX, OS/2, Windows)'#010+
   'A*2WG_Specify graphic type application (Windows)'#010+
   'P*2WG_Specify graphic type application (Classic Mac OS)'#010+
   '3*2Wi_Use internal resources (Darwin)'#010+
-  'P*2Wi_Use internal resources (Darwin)'#010+
-  'p*2Wi_Use internal resources (Dar','win)'#010+
+  'P*2Wi_Use',' internal resources (Darwin)'#010+
+  'p*2Wi_Use internal resources (Darwin)'#010+
   '3*2WN_Do not generate relocation code, needed for debugging (Windows)'#010+
   'A*2WN_Do not generate relocation code, needed for debugging (Windows)'#010+
-  '3*2WR_Generate relocation code (Windows)'#010+
+  '3*2WR_Generate relocation code (W','indows)'#010+
   'A*2WR_Generate relocation code (Windows)'#010+
-  'P*2WT_Specify',' MPW tool type application (Classic Mac OS)'#010+
+  'P*2WT_Specify MPW tool type application (Classic Mac OS)'#010+
   '3*2WX_Enable executable stack (Linux)'#010+
   'A*2WX_Enable executable stack (Linux)'#010+
   'p*2WX_Enable executable stack (Linux)'#010+
-  'P*2WX_Enable executable stack (Linux)'#010+
+  'P*2WX_Enable executa','ble stack (Linux)'#010+
   '**1X_Executable options:'#010+
-  '**2Xc_Pass --shared','/-dynamic to the linker (BeOS, Darwin, FreeBSD, L'+
-  'inux)'#010+
+  '**2Xc_Pass --shared/-dynamic to the linker (BeOS, Darwin, FreeBSD, Lin'+
+  'ux)'#010+
   '**2Xd_Do not use standard library search path (needed for cross compil'+
   'e)'#010+
   '**2Xe_Use external linker'#010+
-  '**2Xg_Create debuginfo in a separate file and add a debuglink section '+
-  'to executable'#010+
-  '**','2XD_Try to link units dynamically      (defines FPC_LINK_DYNAMIC)'#010+
+  '**2Xg_Create debuginfo i','n a separate file and add a debuglink sectio'+
+  'n to executable'#010+
+  '**2XD_Try to link units dynamically      (defines FPC_LINK_DYNAMIC)'#010+
   '**2Xi_Use internal linker'#010+
   '**2Xm_Generate link map'#010+
-  '**2XM<x>_Set the name of the '#039'main'#039' program routine (default i'+
+  '**2XM<x>_Set the name of the '#039'main'#039' program routine (default i',
   's '#039'main'#039')'#010+
-  '**2XP<x>_Prepend the binutils names with the prefix ','<x>'#010+
+  '**2XP<x>_Prepend the binutils names with the prefix <x>'#010+
   '**2Xr<x>_Set the linker'#039's rlink-path to <x> (needed for cross comp'+
   'ile, see the ld manual for more information) (BeOS, Linux)'#010+
-  '**2XR<x>_Prepend <x> to all linker search paths (BeOS, Darwin, FreeBSD'+
-  ', Linux, Mac OS, Solaris)'#010+
-  '**2Xs_Strip all',' symbols from executable'#010+
+  '**2XR<x>_Prepend <x> to all linker search paths (','BeOS, Darwin, FreeB'+
+  'SD, Linux, Mac OS, Solaris)'#010+
+  '**2Xs_Strip all symbols from executable'#010+
   '**2XS_Try to link units statically (default, defines FPC_LINK_STATIC)'#010+
   '**2Xt_Link with static libraries (-static is passed to linker)'#010+
-  '**2XX_Try to smartlink units             (defines FPC_LINK_SMART)'#010+
+  '**2XX_Try to smartli','nk units             (defines FPC_LINK_SMART)'#010+
   '**1*_'#010+
-  '**1?_Show ','this help'#010+
+  '**1?_Show this help'#010+
   '**1h_Shows this help without waiting'
 );

+ 8 - 2
compiler/ogbase.pas

@@ -74,7 +74,9 @@ interface
          { No relocation is needed. It is used in ARM object files.
            Also internal linker use this reloc to make virtual (not real)
            links to some sections }
-         RELOC_NONE
+         RELOC_NONE,
+         { Darwin relocation, using PAIR }
+         RELOC_PIC_PAIR
       );
 
 {$ifndef x86_64}
@@ -143,6 +145,10 @@ interface
        size       : aword;
        { Used for external and common solving during linking }
        exesymbol  : TExeSymbol;
+
+       { Darwin asm is using indirect symbols resolving }
+       indsymbol  : TObjSymbol;
+
        constructor create(AList:TFPHashObjectList;const AName:string);
        function  address:aword;
        procedure SetAddress(apass:byte;aobjsec:TObjSection;abind:TAsmsymbind;atyp:Tasmsymtype);
@@ -536,7 +542,7 @@ implementation
           internalerror(200603016);
         if not assigned(aobjsec) then
           internalerror(200603017);
-        if (bind=AB_EXTERNAL) then
+        if (bind in [AB_EXTERNAL,AB_LAZY]) then
           begin
             bind:=abind;
             typ:=atyp;

+ 1223 - 0
compiler/ogmacho.pas

@@ -0,0 +1,1223 @@
+{
+    Copyright (c) 2009-2010 by Dmitry Boyarintsev
+
+    Contains the binary mach-o writer
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit ogmacho;
+
+{$i fpcdefs.inc}
+
+interface
+
+uses
+  cclasses,
+  globals, globtype, verbose,
+  owbase, ogbase,
+  aasmbase, assemble,
+  macho, machoutils,
+  systems,
+  { assembler }
+  cpuinfo,cpubase,aasmtai,aasmdata; {for system constants}
+
+type
+
+    { TMachoRawWriter }
+
+    TMachoRawWriter=class(TRawWriter)
+      private
+        fwriter : tobjectwriter;
+      public
+        constructor Create(awriter: tobjectwriter);
+        procedure WriteRaw(const data; datasize: Integer); override;
+      end;
+
+    { TmachoObjSection }
+
+    TMachoSectionType=(mst_Normal, mst_ObjC, mst_Stabs, mst_Dwarf);
+
+    TmachoObjSection=class(tObjSection)
+      public
+        nmsegment : string;  {mach-o segment name}
+        nmsection : string;  {mach-o section name}
+
+        inSegIdx  : Integer; {section index inside segment. one-based number}
+        RelocOfs  : aword;   {file offset to the first relocation symbol}
+        IndIndex  : Integer; {index in indirect table (see DysymTableCommand) for lazy and non-lazy symbol pointers}
+
+        machoSec  : TMachoSectionType;
+        function GetRelocCount: Integer;
+        function FileSize: Integer;
+        constructor create(AList:TFPHashObjectList; const Aname:string; Aalign:shortint; Aoptions:TObjSectionOptions);override;
+      end;
+
+    { TmachoObjData }
+
+    TmachoObjData=class(TObjData)
+      public
+        debugcount: Integer;
+        constructor create(const n:string); override;
+        procedure CreateDebugSections; override;
+        function sectionname(atype:TAsmSectiontype; const aname:string; aorder:TAsmSectionOrder):string;override;
+        function sectiontype2align(atype:TAsmSectiontype):shortint;override;
+        function sectiontype2options(atype:TAsmSectiontype):TObjSectionOptions;override;
+        procedure writereloc(data:aint; len:aword; p:TObjSymbol; reltype:TObjRelocationType);override;
+      public
+      end;
+
+    { TMachoObjectOutput }
+
+    TMachoSymbolLocation=(loc_Notused, loc_Local, loc_External, loc_Undef);
+
+    TMachoObjectOutput=class(TObjOutput)
+      private
+        machoData   : TMachoObjData;
+        mfile       : TMachOWriter;
+        cputarget   : cpu_type_t;
+
+        stabsec     : TmachoObjSection;
+        strsec      : TmachoObjSection;
+
+        sectionscnt : integer;
+        memofs      : aword;
+        fileofs     : aword;
+
+        symstrofs   : aword;
+        symlen      : aword;
+        symCount    : aint;
+
+        iLocal      : Integer;
+        iExtern     : Integer;
+        iUndef      : Integer;
+        iIndir      : Integer;
+
+        symList     : TFPObjectList;
+        IndirIndex  : tdynamicarray;
+
+        relcount : integer;
+      protected
+        procedure TrailZeros;
+
+        {sections}
+        procedure FixSectionRelocs(s: TMachoObjSection);
+        procedure section_count_sections(p:TObject;arg:pointer);
+        procedure section_set_datamempos(p:TObject;arg:pointer);
+        procedure section_set_relocpos(p:TObject;arg:pointer);
+
+        procedure section_write_data(p:TObject;arg:pointer);
+        procedure section_write_relocdata(p:TObject;arg:pointer);
+        procedure section_prepare_indirect(s: TObjSection);
+
+        {symbols}
+        procedure symbol_write_nlist(sym:TObjSymbol; symstr: tdynamicarray);
+        function dysymbol_location(sym: TObjSymbol): TMachoSymbolLocation;
+
+        function symWriteName(s: TObjSymbol): string;
+        procedure InitSymbolIndexes(var sCount: aint; var symStrLen: aword);
+
+        {mach-o file related}
+        procedure writeSectionsHeader(s: TMachoObjSection);
+        procedure writeSymTabCommand;
+        procedure writeSymbols(symstr: tdynamicarray);
+        procedure writeDySymTabCommand(IndOffset: aword; IndCount: Integer);
+        procedure writeDysymbols;
+
+        function writedata(data:TObjData):boolean;override;
+      public
+        constructor Create(AWriter:TObjectWriter);override;
+      end;
+
+    { TMachoAssembler }
+
+    TMachoAssembler=class(TInternalAssembler)
+      public
+        constructor create(smart:boolean);override;
+      end;
+
+
+implementation
+
+  { TmachoObjData }
+
+  constructor TmachoObjData.create(const n: string);
+    begin
+      inherited create(n);
+      CObjSection:=TmachoObjSection;
+    end;
+
+
+  { TmachoObjData.CreateDebugSections. }
+  { note: mach-o file has specific symbol table command (not sections) to keep symbols and symbol string }
+  procedure TmachoObjData.CreateDebugSections;
+    begin
+      inherited CreateDebugSections;
+      if target_dbg.id=dbg_stabs then
+        begin
+          stabssec:=createsection(sec_stab);
+          stabstrsec:=createsection(sec_stabstr);
+        end;
+    end;
+
+
+  function TmachoObjData.sectionname(atype: TAsmSectiontype; const aname: string; aorder: TAsmSectionOrder): string;
+    const
+      DwarfSect : array [sec_debug_frame..sec_debug_abbrev] of string
+        = ('sec_debug_frame','__debug_info','__debug_line','__debug_abbrev');
+    begin
+      case atype of
+        sec_bss:  Result:=MakeSectionName(seg_DATA, '__common');
+        sec_stab: Result:='.stabs';
+        sec_stabstr: Result:='.stabsstr';
+        sec_fpc:  Result:=MakeSectionName(seg_TEXT, '.fpc');
+        sec_stub: Result:=MakeSectionName(seg_IMPORT, '__jump_table');
+        sec_code:
+          if (aname='fpc_geteipasebx') or
+             (aname='fpc_geteipasecx') then
+            Result:=MakeSectionName(seg_TEXT, '__textcoal_nt')
+          else
+            Result:=MakeSectionName(seg_TEXT, '__text');
+        sec_rodata_norel: Result:=MakeSectionName(seg_TEXT, '__const'); {.const}
+        sec_rodata:       Result:=MakeSectionName(seg_DATA, '__const');
+        sec_data:         Result:=MakeSectionName(seg_DATA, '__data');
+        sec_data_nonlazy: Result:=MakeSectionName(seg_DATA, '__nl_symbol_ptr');
+        sec_data_lazy:    Result:=MakeSectionName(seg_DATA, '__la_symbol_ptr');
+        sec_init_func:    Result:=MakeSectionName(seg_DATA, '__mod_init_func');
+        sec_term_func:    Result:=MakeSectionName(seg_DATA, '__mod_term_func');
+
+
+        sec_objc_class:           Result:='__OBJC __class';
+        sec_objc_meta_class:      Result:='__OBJC __meta_class';
+        sec_objc_cat_cls_meth:    Result:='__OBJC __cat_cls_meth';
+        sec_objc_cat_inst_meth:   Result:='__OBJC __cat_inst_meth';
+        sec_objc_protocol:      Result:='__OBJC __protocol';
+        sec_objc_string_object: Result:='__OBJC __cstring';
+        sec_objc_cls_meth:        Result:='__OBJC __cls_meth';
+        sec_objc_inst_meth:       Result:='__OBJC __inst_meth';
+        sec_objc_cls_refs:        Result:='__OBJC __cls_refs';
+        sec_objc_message_refs:    Result:='__OBJC __message_refs';
+        sec_objc_symbols:         Result:='__OBJC __symbols';
+        sec_objc_category:      Result:='__OBJC __categories';
+        sec_objc_class_vars:    Result:='__OBJC __cls_vars';
+        sec_objc_instance_vars: Result:='__OBJC __inst_vars';
+        sec_objc_module_info:     Result := '__OBJC __module_info';
+        sec_objc_class_names:     Result:='__TEXT __cstring';
+        sec_objc_meth_var_types: Result:='__OBJC __var_types';
+        sec_objc_meth_var_names:  Result:='__TEXT __cstring';
+        sec_objc_selector_strs: Result:='__TEXT __cstring';
+        sec_objc_protocol_ext:    Result:='__OBJC __protocol_ext';
+        sec_objc_class_ext:       Result:='__OBJC __class_ext';
+        sec_objc_property:        Result:='__OBJC __property';
+        sec_objc_image_info:      Result:='__OBJC __image_info';
+        sec_objc_cstring_object:  Result:='__OBJC __cstring_object';
+        sec_objc_sel_fixup:       Result:='__OBJC __sel_fixup';
+        { Objective-C non-fragile ABI }
+        sec_objc_data:        Result:='__OBJC __data';
+        sec_objc_const:       Result:='__OBJC __const';
+        sec_objc_sup_refs:      Result:='__OBJC __supc_refs';
+        sec_objc_classlist:     Result:='__OBJC __classlist';
+        sec_objc_nlclasslist:   Result:='__OBJC __nlclasslist';
+        sec_objc_catlist:       Result:='__OBJC __catlist';
+        sec_objc_nlcatlist:     Result:='__OBJC __nlcatlist';
+        sec_objc_protolist:     Result:='__OBJC __protolist';
+
+        sec_debug_frame,
+        sec_debug_info,
+        sec_debug_line,
+        sec_debug_abbrev:
+          Result:=MakeSectionName(seg_DWARF, DwarfSect[atype])
+
+      else
+        Result:=MakeSectionName(seg_DATA, '__data');
+      end;
+    end;
+
+
+  procedure TmachoObjData.writereloc(data: aint; len: aword; p: TObjSymbol; reltype: TObjRelocationType);
+    var
+      symaddr : longint;
+    begin
+      {stabs relocation}
+      case TMachoObjSection(CurrObjSec).machoSec of
+
+        mst_Stabs:
+          begin
+            if Assigned(p) then
+              begin
+                data:=p.address;
+                CurrObjSec.addsymreloc(CurrObjSec.Size,p,reltype);
+              end;
+            CurrObjSec.write(data, len);
+          end;
+
+        mst_Dwarf:
+          begin
+            if Assigned(p) then
+              begin
+                CurrObjSec.addsectionReloc(CurrObjSec.Size,p.objsection,reltype);
+                data:=p.address;
+              end;
+            CurrObjSec.write(data, len);
+          end;
+
+      else
+        if assigned(p) then
+          begin
+            { real address of the symbol }
+            symaddr:=p.address;
+            { Local ObjSymbols can be resolved already or need a section reloc }
+            if (p.bind=AB_LOCAL) and
+               (reltype in [RELOC_RELATIVE,RELOC_ABSOLUTE{$ifdef x86_64},RELOC_ABSOLUTE32{$endif x86_64}]) then
+              begin
+                { For a reltype relocation in the same section the value can be calculated }
+                if (p.objsection=CurrObjSec) and
+                   (reltype=RELOC_RELATIVE) then
+                  inc(data,symaddr-len-CurrObjSec.Size)
+                else
+                  begin
+                    if (p.typ=AT_NONE) then
+                      begin
+                        {undefined symbol, using section}
+                        CurrObjSec.addsectionreloc(CurrObjSec.Size,p.objsection,reltype);
+                        data:=symaddr-len-CurrObjSec.Size;
+                      end
+                    else
+                      begin
+                        CurrObjSec.addsymreloc(CurrObjSec.Size,p,reltype);
+                        if Assigned(p.objsection) and
+                           (p.objsection.Name='__TEXT __textcoal_nt') then
+                          data:=symaddr-len-CurrObjSec.Size
+                        else
+                          data:=p.objsection.Size;
+                      end;
+                  end;
+              end
+            else if (p.bind=AB_GLOBAL) and
+                    not Assigned(p.indsymbol) and
+                    (reltype<>RELOC_PIC_PAIR) then
+              begin
+                CurrObjSec.addsectionreloc(CurrObjSec.Size,p.objsection,reltype);
+                data:=p.address;
+              end
+            else
+              CurrObjSec.addsymreloc(CurrObjSec.Size,p,reltype);
+          end; {if assigned(p) }
+
+        CurrObjSec.write(data, len);
+      end;
+    end;
+
+
+  function TmachoObjData.sectiontype2align(atype: TAsmSectiontype): shortint;
+    begin
+      case atype of
+        sec_bss:
+          Result:=4;
+        sec_stabstr, sec_stab:
+          Result:=1;
+        sec_stub, sec_data_lazy, sec_data_nonlazy:
+          Result:=4;
+      else
+        Result:=inherited sectiontype2align(atype);
+      end;
+    end;
+
+
+  function TmachoObjData.sectiontype2options(atype: TAsmSectiontype): TObjSectionOptions;
+    begin
+      case atype of
+        sec_objc_meth_var_names,
+        sec_objc_class_names: Result:=[oso_data, oso_load];
+      else
+        Result:=inherited sectiontype2options(atype);
+      end
+    end;
+
+
+  { TMachoAssembler }
+
+  constructor TMachoAssembler.create(smart: boolean);
+    begin
+      inherited create(smart);
+      CObjOutput:=TMachoObjectOutput;
+    end;
+
+
+  { TMachoObjectOutput }
+
+  procedure TMachoObjectOutput.FixSectionRelocs(s: TMachoObjSection);
+    var
+      i   : integer;
+      ro  : TObjRelocation;
+      dw  : aword;
+    begin
+      {todo: is it I386 only core}
+      if not Assigned(s.Data) then
+        Exit;
+
+      for i:=0 to s.ObjRelocations.Count-1 do
+        begin
+          ro:=TObjRelocation(s.ObjRelocations[i]);
+
+          if (Assigned(ro.objsection)) and
+             (ro.objsection.Name='__TEXT __textcoal_nt') then
+            Continue;
+
+          if Assigned(ro.objsection) then
+            begin
+              s.Data.seek(ro.DataOffset);
+              s.Data.read(dw, sizeof(aword));
+
+              dw:=dw+ro.objsection.MemPos;
+
+              s.Data.seek(ro.DataOffset);
+              s.Data.write(dw, sizeof(aword));
+            end
+          else
+            begin
+              if ro.symbol.Name='fpc_geteipasebx' then
+                Continue;
+              if Assigned(ro.symbol.indsymbol) or
+                 (ro.typ=RELOC_PIC_PAIR) then
+                begin
+                  s.Data.seek(ro.DataOffset);
+                  s.Data.read(dw, sizeof(aword));
+                  dw:=ro.symbol.address-dw;
+                  s.Data.seek(ro.DataOffset);
+                  s.Data.write(dw, sizeof(aword));
+                end
+              else if (ro.symbol.bind=AB_LOCAL) then
+                begin
+                  dw:=ro.symbol.address;
+                  s.Data.seek(ro.DataOffset);
+                  s.Data.write(dw, sizeof(aword));
+                end;
+            end;
+
+        end;
+      s.Data.seek(s.Data.Size);
+    end;
+
+
+  procedure TMachoObjectOutput.section_count_sections(p: TObject; arg: pointer);
+    var
+      s : TMachoObjSection;
+    begin
+      s:=TMachoObjSection(p);
+      if s.machoSec=mst_Stabs then
+        Exit;
+      inc(sectionscnt);
+      s.inSegIdx:=sectionscnt;
+    end;
+
+
+  procedure TMachoObjectOutput.section_set_datamempos(p: TObject; arg: pointer);
+    var
+      s : TMachoObjSection;
+    begin
+      s:=TMachoObjSection(p);
+      if s.machoSec=mst_Stabs then
+        Exit;
+
+      s.setDataPos(fileofs);
+      s.setMemPos(memofs);
+      memofs:=Align(memofs+s.Size, s.SecAlign);
+
+      fileofs:=AlignAddr(cputarget, fileofs);
+    end;
+
+
+  procedure TMachoObjectOutput.section_set_relocpos(p:TObject;arg:pointer);
+    var
+      s   : TMachoObjSection;
+      sz  : Integer;
+    begin
+      s:=TMachoObjSection(p);
+      if s.machoSec=mst_Stabs then
+        Exit;
+
+      sz:=s.GetRelocCount * sizeof(relocation_info);
+      if sz > 0 then
+        begin
+          s.relocofs:=fileofs;
+          inc(fileofs, sz);
+          fileofs:=AlignAddr(cputarget, fileofs);
+        end;
+    end;
+
+
+  procedure TMachoObjectOutput.section_write_data(p: TObject; arg: pointer);
+    var
+      s : TMachoObjSection;
+    begin
+      s:=TMachoObjSection(p);
+      if s.machoSec=mst_Stabs then
+        Exit;
+
+      Writer.writezeros(s.DataAlignBytes);
+
+      FixSectionRelocs(s);
+
+      if s.Datapos<>FWriter.ObjSize then
+        InternalError(200903101);
+      if Assigned(s.data) then
+        Writer.writearray(s.data);
+      TrailZeros;
+    end;
+
+
+  procedure TMachoObjectOutput.section_write_relocdata(p: TObject; arg: pointer);
+    var
+      s       : TMachoObjSection;
+      symsec  : TMachoObjSection;
+      i       : Integer;
+      dw      : aword;
+
+      r       : relocation_info;
+      sr      : scattered_relocation_info;
+      ro      : TObjRelocation;
+      symnum      : Integer;
+      relpc       : Boolean;
+      relextern   : Boolean;
+      reltype     : Integer;
+      spos        : LongWord;
+
+    begin
+      s:=TMachoObjSection(p);
+
+      {stabs relocation should not present in relocation table}
+      if s.machoSec=mst_Stabs then
+        Exit;
+      {no relocation for the section}
+      if s.relocofs=0 then
+        Exit;
+      {check file alignment}
+      if s.relocofs<>FWriter.ObjSize then
+        InternalError(200903102); {file misalignment}
+
+      relcount:=s.ObjRelocations.Count;
+      {the reversed order, is only to be alike Apple linker}
+      for i:=s.ObjRelocations.Count-1 downto 0 do
+      begin
+        ro:=TObjRelocation(s.ObjRelocations[i]);
+
+        {in-section relocation}
+        if ro.symbol=nil then
+          begin
+            relextern:=false;
+            relpc:=false;
+            symnum:=TmachoObjSection(ro.objsection).inSegIdx;
+            case ro.typ of
+              RELOC_ABSOLUTE:
+                begin
+                  RelocInfo(ro.DataOffset, symnum, GENERIC_RELOC_VANILLA, ril_long, relpc, relextern, r);
+                  mfile.WriteRelocation(r);
+                end;
+            else
+              relpc:=ro.typ=RELOC_RELATIVE;
+              RelocInfo(ro.DataOffset, symnum, GENERIC_RELOC_VANILLA, ril_long, relpc, relextern, r);
+              mfile.WriteRelocation(r);
+            end;
+
+          end
+        else
+          begin
+            symsec:=TMachoObjSection(ro.symbol.objsection);
+
+            if Assigned(symsec) and
+               (symsec.Name='__TEXT __textcoal_nt') then
+              begin
+                relextern:=true;
+                symnum:=ro.symbol.symidx;
+              end
+            else if ro.symbol.bind=AB_EXTERNAL then
+              begin
+                relextern:=true;
+                symnum:=ro.symbol.symidx;
+              end
+            else if Assigned(ro.symbol.objsection) and
+                    (ro.symbol.bind=AB_LOCAL) and
+                    (ro.symbol.typ=AT_DATA) then
+              begin
+                relextern:=false;
+                symnum:=TMachoObjSection(ro.symbol.objsection).inSegIdx;
+              end
+            else if (ro.symbol.bind=AB_LOCAL) or
+                    (ro.symbol.typ=AT_NONE) then
+             begin
+               relextern:=false;
+                symnum:=s.inSegIdx
+              end
+            else
+              begin
+                relextern:=true;
+                symnum:=ro.symbol.symidx;
+              end;
+
+            relpc:=false;
+            relpc:=(ro.typ=RELOC_RELATIVE);
+            if (ro.typ=RELOC_PIC_PAIR) then
+              begin
+                if ro.symbol.bind=AB_LOCAL then
+                  reltype:=GENERIC_RELOC_LOCAL_SECTDIFF
+                else
+                  reltype:=GENERIC_RELOC_SECTDIFF;
+                ScatterRelocInfo(ro.symbol.address, ro.DataOffset, reltype, ril_long, false, sr);
+                mfile.WriteScatterReloc(sr);
+
+                { the section data is already fixed to:   ro.SymbolOffset - Label.Offset }
+                s.Data.seek(ro.DataOffset);
+                s.Data.read(dw, sizeof(aword));
+                dw:=ro.symbol.address-dw;
+                ScatterRelocInfo(dw, 0, GENERIC_RELOC_PAIR, ril_long, false, sr);
+                mfile.WriteScatterReloc(sr);
+              end
+            else
+              begin
+                RelocInfo(ro.DataOffset, symnum, GENERIC_RELOC_VANILLA, ril_long, relpc, relextern, r);
+                mfile.WriteRelocation(r);
+              end
+          end;
+        if Assigned(s.Data) then
+          s.Data.seek(s.Data.size);
+      end;
+      TrailZeros;
+    end;
+
+
+    procedure TMachoObjectOutput.section_prepare_indirect(s: TObjSection);
+      var
+        t       : TObjSymbol;
+        i       : Integer;
+        anysym  : Boolean;
+      begin
+        if TmachoObjSection(s).machoSec=mst_Stabs then
+          Exit;
+
+        anysym:=false;
+        for i:=0 to machoData.ObjSymbolList.Count-1 do
+          begin
+            t:=TObjSymbol(machoData.ObjSymbolList[i]);
+            if (t.objsection=s) and Assigned(t.indsymbol) then
+              begin
+                if not anysym then
+                  begin
+                    {remember the index of the first indirect symbol. Will be used later at section header writting}
+                    TmachoObjSection(s).indIndex:=IndirIndex.size div SizeOf(Integer);
+                    anysym:=true;
+                  end;
+                IndirIndex.write(t.symidx, sizeof(Integer));
+              end;
+          end;
+
+      end;
+
+
+    procedure TMachoObjectOutput.symbol_write_nlist(sym:TObjSymbol; symstr: tdynamicarray);
+      var
+        n       : nlist_64;
+        sec     : TmachoObjSection;
+      begin
+        sec:=TMachoObjSection(sym.objsection);
+        FillChar(n, sizeof(n), 0);
+        n.n_un.n_strx:=symstr.size;
+        symstr.writestr(sym.Name+#0);
+
+        if assigned(sec) and
+           (sec.machoSec=mst_ObjC) and
+           (sec.nmsection='__module_info') then
+          begin
+            n.n_type:=N_ABS or N_EXT;
+            mfile.WriteNList(n);
+            Exit;
+          end;
+
+        if (sym.typ=AT_NONE) then
+          begin
+            n.n_value:=0;
+            if sym.bind<>AB_EXTERNAL then
+              n.n_desc:=n.n_desc or REFERENCE_FLAG_UNDEFINED_LAZY;
+            n.n_type:=n.n_type or N_EXT;
+          end
+        else if sym.bind=AB_LAZY then
+          begin
+            n.n_value:=0;
+            n.n_type:=N_ABS or N_EXT;
+            n.n_sect:=NO_SECT;
+          end
+        else
+          begin
+            n.n_value:=sym.address;
+
+            if Assigned(sec) then
+              begin
+                n.n_sect:=sec.inSegIdx;
+                n.n_type:=n.n_type or N_SECT;
+
+                if (sym.typ=AT_FUNCTION) and
+                   (sym.bind=AB_LOCAL) then
+                  begin
+                    n.n_type:=N_PEXT or N_EXT or N_SECT;
+                    n.n_desc:=n.n_desc or N_WEAK_DEF;
+                  end;
+              end;
+          end;
+
+        if (sym.bind=AB_GLOBAL) and
+           (n.n_type and N_PEXT=0) then
+          n.n_type:=n.n_type or N_EXT;
+
+        if (sym.typ=AT_FUNCTION) and
+           (sym.bind=AB_GLOBAL) then
+          n.n_desc:=n.n_desc or N_NO_DEAD_STRIP;
+
+        if Assigned(sec) then
+          begin
+            if (sec.nmsection='__nl_symbol_ptr') then
+              n.n_desc:=n.n_desc or REFERENCE_FLAG_UNDEFINED_NON_LAZY;
+            if (sec.nmsegment=seg_Data) and (sec.nmsection='__const') then
+              n.n_desc:=n.n_desc or N_NO_DEAD_STRIP;
+          end;
+
+        mfile.WriteNList(n);
+      end;
+
+
+    function TMachoObjectOutput.dysymbol_location(sym: TObjSymbol): TMachoSymbolLocation;
+      begin
+        if Assigned(sym.objsection) and
+           (TMachoObjSection(sym.objsection).machoSec=mst_Stabs) then
+          Result:=loc_Local
+        else
+          case sym.typ of
+            AT_NONE:  Result:=loc_Undef;
+            AT_LABEL: Result:=loc_Notused;
+          else
+            Result:=loc_External;
+          end;
+      end;
+
+
+  procedure TMachoObjectOutput.writeSectionsHeader(s: TMachoObjSection);
+    var
+      sc      : TMachoSection;
+    begin
+      section_prepare_indirect(s);
+
+      fillChar(sc, sizeof(sc), 0);
+      sc.segname:=s.nmsegment;
+      sc.sectname:=s.nmsection;
+      sc.size:=s.Size;
+      if s.FileSize>0 then
+        sc.offset:=s.DataPos
+      else
+        sc.offset:=0;
+      sc.addr:=s.MemPos;
+      sc.nreloc:=s.GetRelocCount;
+      sc.reloff:=s.relocofs;
+      sc.flags:=GetSectionFlags(s.nmsegment, s.nmsection);
+      sc.align:=MachoAlign(s.SecAlign);
+      sc.indirectIndex:=s.indIndex;
+
+      if (sc.flags and SECTION_TYPE)=S_SYMBOL_STUBS then
+        sc.stubSize:=GetStubSize(cputarget, false);
+      mfile.WriteSection(sc);
+    end;
+
+
+  procedure TMachoObjectOutput.writeSymTabCommand;
+    begin
+      mfile.WriteLoadCommand(LC_SYMTAB, sizeof(symtab_command));
+      mfile.WriteUint32(fileofs); {symoff}
+      mfile.WriteUint32(symCount); {nsyms}
+      inc(fileofs, symCount*sizeNList(cputarget));
+      fileofs:=AlignAddr(cputarget, fileofs);
+
+      symstrofs:=fileofs;
+      mfile.WriteUint32(fileofs); {stroff}
+      mfile.WriteUint32(symlen); {strsize}
+
+      inc(fileofs, symlen);
+      fileofs:=AlignAddr(cputarget, fileofs);
+    end;
+
+
+    function TMachoObjectOutput.symWriteName(s: TObjSymbol): string;
+      begin
+        if not Assigned(s.indsymbol) then
+          Result:=s.Name
+        else
+          Result:=s.indsymbol.Name;
+      end;
+
+
+{    function getSymWriteNameLength(s: TObjSymbol): Integer; inline;
+      begin
+        Result:=length(symWriteName(s))+1;
+      end;}
+
+
+    procedure TMachoObjectOutput.InitSymbolIndexes(var sCount: aint; var symStrLen: aword);
+      var
+        i         : integer;
+        s         : TObjSymbol;
+        stabcount : Integer;
+      begin
+        sCount:=0;
+        symStrLen:=0;
+
+        iIndir:=0;
+        for i:=0 to machoData.ObjSymbolList.Count-1 do
+          begin
+            s:=TObjSymbol(machoData.ObjSymbolList[i]);
+            if (s.typ=AT_LABEL) then
+              Continue;
+
+            if Assigned(s.indsymbol) then
+              inc(iIndir);
+          end;
+
+        iLocal:=0;
+        iExtern:=0;
+        iUndef:=0;
+
+        for i:=0 to machoData.ObjSymbolList.Count-1 do
+          begin
+            s:=TObjSymbol(machoData.ObjSymbolList[i]);
+            if (s.typ=AT_LABEL) or
+               Assigned(s.indsymbol) then
+                 Continue;
+            if (s.bind=AB_LOCAL) and
+               (s.Name <> 'fpc_geteipasebx') then
+              Continue;
+
+            case dysymbol_location(s) of
+              loc_Local:
+                begin
+                  symList.Insert(iLocal, s);
+                  inc(iLocal); inc(iExtern); inc(iUndef);
+                end;
+              loc_External:
+                begin
+                  symList.Insert(iExtern, s);
+                  inc(iExtern); inc(iUndef);
+                end;
+              loc_Undef:
+                begin
+                  symList.Insert(iUndef, s);
+                  inc(iUndef);
+                end;
+            end;
+            inc(symStrLen, length(s.Name)+1 );
+          end;
+
+        if Assigned(stabsec) then
+          {skipping hdrsym! (added by ogbase) }
+          stabcount:=stabsec.Size div sizeof(TObjStabEntry) - 1
+        else
+          stabcount:=0;
+
+        for i:=0 to symList.Count-1 do
+          TObjSymbol(symList[i]).symidx:=i+stabcount;
+        sCount:=symList.Count+stabcount;
+
+        for i:=0 to machoData.ObjSymbolList.Count-1 do
+          with TObjSymbol(machoData.ObjSymbolList[i]) do
+            if Assigned(indsymbol) then
+              symidx:=indsymbol.symidx;
+
+        if Assigned(strsec) then
+          // 1 byte of zero name (that stands in the end of table, not at zero pos)
+          inc(symlen, strsec.Size + 1)
+        else
+          inc(symlen); {the first zero byte}
+
+        dec(iUndef, iExtern); { iUndef is count of undefined symbols (for dysymtable command) }
+        dec(iExtern, iLocal); { iExtern is count of external symbols (for dysymtable command) }
+        inc(iLocal, stabcount);
+      end;
+
+
+    procedure TMachoObjectOutput.writeSymbols(symstr: tdynamicarray);
+      var
+        i       : integer;
+        s       : TObjSymbol;
+        b       : byte;
+        stab    : TObjStabEntry;
+        ro      : TObjRelocation;
+        sym     : TObjSymbol;
+        addr    : aword;
+        text    : TmachoObjSection;
+        funofs  : AWord;
+      begin
+        if Assigned(stabsec) then
+          begin
+            for i:=0 to stabsec.ObjRelocations.Count - 1 do
+              begin
+                ro:=TObjRelocation(stabsec.ObjRelocations[i]);
+                sym:=ro.symbol;
+                addr:=sym.address;
+                if Assigned(sym.objsection) then
+                  begin
+                    stabsec.Data.seek(ro.DataOffset-3);
+                    b:=TmachoObjSection(sym.objsection).inSegIdx;
+                    stabsec.Data.write(b, sizeof(b));
+                  end;
+                stabsec.Data.seek(ro.DataOffset);
+                stabsec.Data.write(addr, sizeof(addr));
+              end;
+
+            stabsec.Data.seek(sizeof(TObjStabEntry));
+            funofs:=0;
+            text:=TmachoObjSection(machoData.ObjSectionList.Find(MakeSectionName(seg_TEXT, '__text')));
+            for i:=1 to stabsec.Data.size div SizeOf(TObjStabEntry) - 1 do
+              begin
+                stabsec.Data.read(stab, sizeof(stab));
+                case stab.ntype of
+                  N_FUN:
+                    begin
+                      if stab.strpos=0 then
+                        funofs:=0
+                      else
+                        funofs:=stab.nvalue;
+                    end;
+                  N_SLINE,N_RBRAC,N_LBRAC:
+                    begin
+                      if Assigned(text) then
+                        begin
+                          { SLINE are expected to be in  __TEXT __text only }
+                          stab.nother:=text.inSegIdx;
+                          inc(stab.nvalue, funofs);
+                        end;
+                    end;
+                  N_OSO:
+                    begin
+                      { null-terminated string is the first in the list         }
+                      { apple-gdb doesn't recognize it as zero-string for N_OSO }
+                      { another zero-string should be added to the list         }
+                      if stab.strpos=0 then
+                        stab.strpos:=symstr.Size;
+                    end;
+                end;
+                FWriter.write(stab, sizeof(stab));
+              end;
+          end;
+
+        symstr.Seek(symStr.size);
+        b:=0;
+        symstr.Write(b,1);
+
+        for i:=0 to symList.Count-1 do
+          begin
+            s:=TObjSymbol(symList[i]);
+            symbol_write_nlist(s, symstr);
+          end;
+      end;
+
+
+  procedure TMachoObjectOutput.writeDySymTabCommand(IndOffset: aword; IndCount: Integer);
+    begin
+      mfile.WriteLoadCommand(LC_DYSYMTAB, sizeof(dysymtab_command));
+
+      mfile.WriteUint32(0); {ilocalsym}
+      mfile.WriteUint32(iLocal); {nlocalsym}
+
+      mfile.WriteUint32(iLocal); {iextdefsym}
+      mfile.WriteUint32(iExtern); {nextdefsym}
+
+      mfile.WriteUint32(iLocal + iExtern); {iundefsym}
+      mfile.WriteUint32(iUndef); {nundefsym}
+
+      mfile.WriteUint32(0); {tocoff}
+      mfile.WriteUint32(0); {ntoc}
+      mfile.WriteUint32(0); {modtaboff}
+      mfile.WriteUint32(0); {nmodtab}
+      mfile.WriteUint32(0); {extrefsymoff}
+      mfile.WriteUint32(0); {nextrefsyms}
+      mfile.WriteUint32(IndOffset);  {indirectsymoff}
+      mfile.WriteUint32(IndCount);   {nindirectsyms}
+      mfile.WriteUint32(0); {extreloff}
+      mfile.WriteUint32(0); {nextrel}
+      mfile.WriteUint32(0); {locreloff}
+      mfile.WriteUint32(0); {nlocrel}
+    end;
+
+
+  procedure TMachoObjectOutput.writeDysymbols;
+    var
+      i   : integer;
+      idx : LongWord;
+    begin
+      IndirIndex.seek(0);
+      for i:=0 to (IndirIndex.size div sizeof(Integer))-1 do
+        begin
+          IndirIndex.read(idx, sizeof(idx));
+          mfile.WriteUint32(idx);
+        end;
+    end;
+
+
+  function AddSectionToSegment(var segment: TMachoSegment; section : TMachoObjSection): boolean;
+    begin
+      { sections must be attached one-by-one to the segment }
+      if segment.fileoff=0 then
+        segment.fileoff:=section.DataPos;
+
+      if (segment.fileoff+segment.filesize)<(section.FileSize+section.DataPos) then
+        segment.filesize:=section.FileSize+section.DataPos;
+
+      inc(segment.nsects);
+      inc(segment.vmsize, section.size);
+      Result:=true;
+   end;
+
+
+  procedure TMachoObjectOutput.TrailZeros;
+    var
+      sz : LongWord;
+    begin
+      sz:=AlignAddr(cputarget, FWriter.Size);
+      if sz - FWriter.Size>0 then
+        FWriter.WriteZeros(sz-FWriter.Size);
+    end;
+
+
+  function TMachoObjectOutput.writedata(data: TObjData): boolean;
+    var
+      header  : TMachHeader;
+      seg     : TMachoSegment;
+      secobj  : TMachoObjSection;
+      i       : Integer;
+
+      symstr  : tdynamicarray;
+      segSize : integer; {size of a segment command - platform dependant}
+      sctSize : integer; {size of a single section header - platform dependant}
+
+      indOfs: aword;   {indirect symbol offset}
+
+    begin
+      symList:=TFPObjectList.Create(false);
+      IndirIndex:=tdynamicarray.Create(1024);
+
+      result:=false;
+      machoData:=TMachoObjData(data);
+
+      cputarget:=CPU_TYPE_i386;
+      segSize:=sizeSegment(cputarget);
+      sctSize:=sizeSection(cputarget);
+
+      sectionscnt:=0;
+      stabsec:=TMachoObjSection(machoData.ObjSectionList.Find('.stabs'));
+      strsec:=TMachoObjSection(machoData.ObjSectionList.Find('.stabsstr'));
+
+      {count number of sections}
+      machoData.ObjSectionList.ForEachCall(@section_count_sections, nil);
+
+      {sections data is written after machheader,load-commands.   }
+      {   basic loadcommands for MH_OBJECT are                    }
+      {   single LC_SEGMENT, containing all sections headers      }
+      {   symbol linking information at LC_SYMTAB and LC_DYSYMTAB }
+      header.cputype:=cputarget;
+      header.cpusubtype:=CPU_SUBTYPE_i386_ALL;
+      header.filetype:=MH_OBJECT;
+      header.ncmds:=3;
+      header.sizeofcmds:=segSize+sctSize*sectionscnt+sizeof(symtab_command)+sizeof(dysymtab_command);
+      header.flags:=0;
+
+      {setting sections data and memory pos}
+      fileofs:=sizeMachHeader(cputarget)+header.sizeofcmds;
+      fileofs:=AlignAddr(cputarget, fileofs);
+      memofs:=0;
+
+      machoData.ObjSectionList.ForEachCall(@section_set_datamempos, nil);
+      fileofs:=AlignAddr(cputarget, fileofs);
+
+      {setting sections relocation offsets}
+      machoData.ObjSectionList.ForEachCall(@section_set_relocpos, nil);
+      fileofs:=AlignAddr(cputarget, fileofs);
+
+      {creating actual mach-o file writer}
+      mfile:=AllocMachoWriter(CPU_TYPE_I386, TMachoRawWriter.Create(writer), true);
+      {writing macho-o header}
+      mfile.WriteHeader(header);
+
+      {starting the first segment command}
+      InitSegment(seg);
+
+      {initialze symbols. some sections (non_lazy, lazy pointers) are effected}
+      InitSymbolIndexes(symCount, symlen);
+
+      for i:=0 to machoData.ObjSectionList.Count-1 do
+        begin
+          secobj:=TmachoObjSection(machoData.ObjSectionList[i]);
+          if secobj.machoSec=mst_Stabs then
+            Continue;
+          AddSectionToSegment(seg, secobj);
+        end;
+
+      {writting segment command}
+      {for MH_OBJECT, all sections are stored in the single segment}
+      mfile.WriteSegmentCmd(seg, segSize+(seg.nsects)*sctSize);
+
+      {section headers are written inside segment command}
+      for i:=0 to machoData.ObjSectionlist.Count - 1 do
+        begin
+          secobj:=TmachoObjSection(machoData.ObjSectionList[i]);
+          if secobj.machoSec=mst_Stabs then
+            Continue;
+          writeSectionsHeader(secobj);
+        end;
+      TrailZeros;
+
+      if IndirIndex.size div sizeof(Integer)<>iIndir then
+        InternalError(2009121001);
+      if iIndir>0 then
+        indOfs:=fileOfs
+      else
+        indOfs:=0;
+      inc(fileofs, IndirIndex.size);
+
+      {write symtab command}
+      {initilize symbos order. local first, extern second, undef last}
+      writeSymTabCommand;
+      TrailZeros;
+
+      {write dysymtab command}
+      writeDySymTabCommand(indofs, iIndir);
+      TrailZeros;
+
+      {writting sections data, to precalculated offsets}
+      {if precalculated offsets, doesn't match actual written offsets, internal error is risen}
+      machoData.ObjSectionList.ForEachCall(@section_write_data, nil);
+
+      {writting relocation offsets}
+      machoData.ObjSectionList.ForEachCall(@section_write_relocdata, nil);
+
+      {writting dyn symbol tables (indirect symbols arrays)}
+      writeDysymbols;
+
+      {writting symbol table}
+      if Assigned(strsec) then
+        symstr:=strsec.Data
+      else
+        symstr:=tdynamicarray.create(1024);
+
+      writeSymbols(symstr);
+      TrailZeros;
+
+      {writting symbol table strings}
+      FWriter.writearray(symstr);
+      // terminating null name
+      TrailZeros;
+
+      if not Assigned(strsec) then
+        symstr.Free;
+
+      TrailZeros;
+
+      mfile.Free;
+      symList.Free;
+      IndirIndex.Free;
+    end;
+
+
+  constructor TMachoObjectOutput.Create(AWriter: TObjectWriter);
+    begin
+      inherited Create(AWriter);
+      CObjData:=TMachoObjData;
+    end;
+
+
+  { TMachoRawWriter }
+
+  constructor TMachoRawWriter.Create(awriter: tobjectwriter);
+    begin
+      inherited Create;
+      fwriter:=awriter;
+    end;
+
+
+  procedure TMachoRawWriter.WriteRaw(const data; datasize: Integer);
+    begin
+      fwriter.Write(data, datasize);
+    end;
+
+
+  { TmachoObjSection }
+
+  function TmachoObjSection.GetRelocCount: Integer;
+    var
+      i: integer;
+      r: TObjRelocation;
+    begin
+      Result:=ObjRelocations.Count;
+      for i:=0 to ObjRelocations.Count-1 do
+        begin
+          r:=TObjRelocation(ObjRelocations[i]);
+          if (r.typ=RELOC_PIC_PAIR) then
+            inc(Result);
+        end;
+    end;
+
+
+  function TmachoObjSection.FileSize: Integer;
+    begin
+      if Assigned(data) then
+        Result:=data.size
+      else
+        Result:=0;
+    end;
+
+
+  constructor TmachoObjSection.create(AList: TFPHashObjectList;
+    const Aname: string; Aalign: shortint; Aoptions: TObjSectionOptions);
+    begin
+      if Aname = '__TEXT __textcoal_nt' then
+        Aalign:=4;
+
+      inherited create(AList, Aname, Aalign, Aoptions);
+      GetSegmentSectionName(aName, nmsegment, nmsection);
+      if (aname='.stabs') or
+         (aname='.stabsstr') then
+        machoSec:=mst_Stabs
+      else if nmsegment=seg_DWARF then
+        machoSec:=mst_Dwarf
+      else if nmsegment=seg_OBJC then
+        machoSec:=mst_ObjC
+      else
+        machoSec:=mst_Normal;
+    end;
+
+
+  const
+    as_i386_darwin_info : tasminfo =
+      (
+        id     : as_i386_macho;
+        idtxt  : 'MACHO';
+        asmbin : '';
+        asmcmd : '';
+        supported_targets : [system_i386_darwin];
+        flags : [af_outputbinary,af_smartlink_sections,af_supports_dwarf{, af_stabs_use_function_absolute_addresses}];
+        labelprefix : '.L';
+        comment : '#';
+      );
+
+initialization
+  RegisterAssembler(as_i386_darwin_info,TMachoAssembler);
+
+end.
+

+ 1 - 0
compiler/systems.pas

@@ -173,6 +173,7 @@ interface
              ,as_m68k_mit
              ,as_powerpc_mpw
              ,as_darwin
+             ,as_i386_macho
              ,as_x86_64_masm
              ,as_x86_64_pecoff
              ,as_i386_pecoffwince

+ 9 - 0
compiler/x86/aasmcpu.pas

@@ -1969,6 +1969,7 @@ implementation
         rfield,
         data,s,opidx : longint;
         ea_data : ea;
+        relsym : TObjSymbol;
       begin
         { safety check }
         if objdata.currobjsec.size<>longword(insoffset) then
@@ -2303,6 +2304,14 @@ implementation
                            else
 {$endif x86_64}
                              currabsreloc:=RELOC_ABSOLUTE32;
+
+                           if (currabsreloc=RELOC_ABSOLUTE32) and
+                            (Assigned(oper[opidx]^.ref^.relsymbol)) then
+                           begin
+                             relsym:=objdata.symbolref(oper[opidx]^.ref^.relsymbol);
+                             currabsreloc:=RELOC_PIC_PAIR;
+                             currval:=relsym.offset;
+                           end;
                          objdata.writereloc(currval,ea_data.bytes,currsym,currabsreloc);
                          inc(s,ea_data.bytes);
                        end;