Home | History | Annotate | Line # | Download | only in libiberty
      1   1.1  christos /* simple-object-mach-o.c -- routines to manipulate Mach-O object files.
      2  1.10  christos    Copyright (C) 2010-2025 Free Software Foundation, Inc.
      3   1.1  christos    Written by Ian Lance Taylor, Google.
      4   1.1  christos 
      5   1.1  christos This program is free software; you can redistribute it and/or modify it
      6   1.1  christos under the terms of the GNU General Public License as published by the
      7   1.1  christos Free Software Foundation; either version 2, or (at your option) any
      8   1.1  christos later version.
      9   1.1  christos 
     10   1.1  christos This program is distributed in the hope that it will be useful,
     11   1.1  christos but WITHOUT ANY WARRANTY; without even the implied warranty of
     12   1.1  christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13   1.1  christos GNU General Public License for more details.
     14   1.1  christos 
     15   1.1  christos You should have received a copy of the GNU General Public License
     16   1.1  christos along with this program; if not, write to the Free Software
     17   1.1  christos Foundation, 51 Franklin Street - Fifth Floor,
     18   1.1  christos Boston, MA 02110-1301, USA.  */
     19   1.1  christos 
     20   1.1  christos #include "config.h"
     21   1.1  christos #include "libiberty.h"
     22   1.1  christos #include "simple-object.h"
     23   1.1  christos 
     24   1.1  christos #include <stddef.h>
     25   1.1  christos 
     26   1.1  christos #ifdef HAVE_STDLIB_H
     27   1.1  christos #include <stdlib.h>
     28   1.1  christos #endif
     29   1.1  christos 
     30   1.1  christos #ifdef HAVE_STDINT_H
     31   1.1  christos #include <stdint.h>
     32   1.1  christos #endif
     33   1.1  christos 
     34   1.1  christos #ifdef HAVE_STRING_H
     35   1.1  christos #include <string.h>
     36   1.1  christos #endif
     37   1.1  christos 
     38   1.1  christos #ifdef HAVE_INTTYPES_H
     39   1.1  christos #include <inttypes.h>
     40   1.1  christos #endif
     41   1.1  christos 
     42   1.1  christos #include "simple-object-common.h"
     43   1.1  christos 
     44   1.1  christos /* Mach-O structures and constants.  */
     45   1.1  christos 
     46   1.1  christos /* Mach-O header (32-bit version).  */
     47   1.1  christos 
     48   1.1  christos struct mach_o_header_32
     49   1.1  christos {
     50   1.1  christos   unsigned char magic[4];	/* Magic number.  */
     51   1.1  christos   unsigned char cputype[4];	/* CPU that this object is for.  */
     52   1.1  christos   unsigned char cpusubtype[4];	/* CPU subtype.  */
     53   1.1  christos   unsigned char filetype[4];	/* Type of file.  */
     54   1.1  christos   unsigned char ncmds[4];	/* Number of load commands.  */
     55   1.1  christos   unsigned char sizeofcmds[4];	/* Total size of load commands.  */
     56   1.1  christos   unsigned char flags[4];	/* Flags for special featues.  */
     57   1.1  christos };
     58   1.1  christos 
     59   1.1  christos /* Mach-O header (64-bit version).  */
     60   1.1  christos 
     61   1.1  christos struct mach_o_header_64
     62   1.1  christos {
     63   1.1  christos   unsigned char magic[4];	/* Magic number.  */
     64   1.1  christos   unsigned char cputype[4];	/* CPU that this object is for.  */
     65   1.1  christos   unsigned char cpusubtype[4];	/* CPU subtype.  */
     66   1.1  christos   unsigned char filetype[4];	/* Type of file.  */
     67   1.1  christos   unsigned char ncmds[4];	/* Number of load commands.  */
     68   1.1  christos   unsigned char sizeofcmds[4];	/* Total size of load commands.  */
     69   1.1  christos   unsigned char flags[4];	/* Flags for special featues.  */
     70   1.1  christos   unsigned char reserved[4];	/* Reserved.  Duh.  */
     71   1.1  christos };
     72   1.1  christos 
     73   1.1  christos /* For magic field in header.  */
     74   1.1  christos 
     75   1.1  christos #define MACH_O_MH_MAGIC			0xfeedface
     76   1.1  christos #define MACH_O_MH_MAGIC_64		0xfeedfacf
     77   1.1  christos 
     78   1.1  christos /* For filetype field in header.  */
     79   1.1  christos 
     80   1.1  christos #define MACH_O_MH_OBJECT		0x01
     81   1.1  christos 
     82   1.1  christos /* A Mach-O file is a list of load commands.  This is the header of a
     83   1.1  christos    load command.  */
     84   1.1  christos 
     85   1.1  christos struct mach_o_load_command
     86   1.1  christos {
     87   1.1  christos   unsigned char cmd[4];		/* The type of load command.  */
     88   1.1  christos   unsigned char cmdsize[4];	/* Size in bytes of entire command.  */
     89   1.1  christos };
     90   1.1  christos 
     91   1.1  christos /* For cmd field in load command.   */
     92   1.1  christos 
     93   1.1  christos #define MACH_O_LC_SEGMENT		0x01
     94   1.1  christos #define MACH_O_LC_SEGMENT_64		0x19
     95   1.1  christos 
     96   1.1  christos /* LC_SEGMENT load command.  */
     97   1.1  christos 
     98   1.1  christos struct mach_o_segment_command_32
     99   1.1  christos {
    100   1.1  christos   unsigned char cmd[4];		/* The type of load command (LC_SEGMENT).  */
    101   1.1  christos   unsigned char cmdsize[4];	/* Size in bytes of entire command.  */
    102   1.1  christos   unsigned char segname[16];	/* Name of this segment.  */
    103   1.1  christos   unsigned char vmaddr[4];	/* Virtual memory address of this segment.  */
    104   1.1  christos   unsigned char vmsize[4];	/* Size there, in bytes.  */
    105   1.1  christos   unsigned char fileoff[4];	/* Offset in bytes of the data to be mapped.  */
    106   1.1  christos   unsigned char filesize[4];	/* Size in bytes on disk.  */
    107   1.1  christos   unsigned char maxprot[4];	/* Maximum permitted vmem protection.  */
    108   1.1  christos   unsigned char initprot[4];	/* Initial vmem protection.  */
    109   1.1  christos   unsigned char nsects[4];	/* Number of sections in this segment.  */
    110   1.1  christos   unsigned char flags[4];	/* Flags that affect the loading.  */
    111   1.1  christos };
    112   1.1  christos 
    113   1.1  christos /* LC_SEGMENT_64 load command.  */
    114   1.1  christos 
    115   1.1  christos struct mach_o_segment_command_64
    116   1.1  christos {
    117   1.1  christos   unsigned char cmd[4];		/* The type of load command (LC_SEGMENT_64).  */
    118   1.1  christos   unsigned char cmdsize[4];	/* Size in bytes of entire command.  */
    119   1.1  christos   unsigned char segname[16];	/* Name of this segment.  */
    120   1.1  christos   unsigned char vmaddr[8];	/* Virtual memory address of this segment.  */
    121   1.1  christos   unsigned char vmsize[8];	/* Size there, in bytes.  */
    122   1.1  christos   unsigned char fileoff[8];	/* Offset in bytes of the data to be mapped.  */
    123   1.1  christos   unsigned char filesize[8];	/* Size in bytes on disk.  */
    124   1.1  christos   unsigned char maxprot[4];	/* Maximum permitted vmem protection.  */
    125   1.1  christos   unsigned char initprot[4];	/* Initial vmem protection.  */
    126   1.1  christos   unsigned char nsects[4];	/* Number of sections in this segment.  */
    127   1.1  christos   unsigned char flags[4];	/* Flags that affect the loading.  */
    128   1.1  christos };
    129   1.1  christos 
    130   1.1  christos /* 32-bit section header.  */
    131   1.1  christos 
    132   1.1  christos struct mach_o_section_32
    133   1.1  christos {
    134   1.1  christos   unsigned char sectname[16];	/* Section name.  */
    135   1.1  christos   unsigned char segname[16];	/* Segment that the section belongs to.  */
    136   1.1  christos   unsigned char addr[4];	/* Address of this section in memory.  */
    137   1.1  christos   unsigned char size[4];	/* Size in bytes of this section.  */
    138   1.1  christos   unsigned char offset[4];	/* File offset of this section.  */
    139   1.1  christos   unsigned char align[4];	/* log2 of this section's alignment.  */
    140   1.1  christos   unsigned char reloff[4];	/* File offset of this section's relocs.  */
    141   1.1  christos   unsigned char nreloc[4];	/* Number of relocs for this section.  */
    142   1.1  christos   unsigned char flags[4];	/* Section flags/attributes.  */
    143   1.1  christos   unsigned char reserved1[4];
    144   1.1  christos   unsigned char reserved2[4];
    145   1.1  christos };
    146   1.1  christos 
    147   1.1  christos /* 64-bit section header.  */
    148   1.1  christos 
    149   1.1  christos struct mach_o_section_64
    150   1.1  christos {
    151   1.1  christos   unsigned char sectname[16];	/* Section name.  */
    152   1.1  christos   unsigned char segname[16];	/* Segment that the section belongs to.  */
    153   1.1  christos   unsigned char addr[8];	/* Address of this section in memory.  */
    154   1.1  christos   unsigned char size[8];	/* Size in bytes of this section.  */
    155   1.1  christos   unsigned char offset[4];	/* File offset of this section.  */
    156   1.1  christos   unsigned char align[4];	/* log2 of this section's alignment.  */
    157   1.1  christos   unsigned char reloff[4];	/* File offset of this section's relocs.  */
    158   1.1  christos   unsigned char nreloc[4];	/* Number of relocs for this section.  */
    159   1.1  christos   unsigned char flags[4];	/* Section flags/attributes.  */
    160   1.1  christos   unsigned char reserved1[4];
    161   1.1  christos   unsigned char reserved2[4];
    162   1.1  christos   unsigned char reserved3[4];
    163   1.1  christos };
    164   1.1  christos 
    165   1.1  christos /* Flags for Mach-O sections.  */
    166   1.1  christos 
    167   1.1  christos #define MACH_O_S_ATTR_DEBUG			0x02000000
    168   1.1  christos 
    169   1.1  christos /* The length of a segment or section name.  */
    170   1.1  christos 
    171   1.1  christos #define MACH_O_NAME_LEN (16)
    172   1.1  christos 
    173   1.1  christos /* A GNU specific extension for long section names.  */
    174   1.1  christos 
    175   1.1  christos #define GNU_SECTION_NAMES "__section_names"
    176   1.1  christos 
    177   1.1  christos /* A GNU-specific extension to wrap multiple sections using three
    178   1.1  christos    mach-o sections within a given segment.  The section '__wrapper_sects'
    179   1.1  christos    is subdivided according to the index '__wrapper_index' and each sub
    180   1.1  christos    sect is named according to the names supplied in '__wrapper_names'.  */
    181   1.1  christos 
    182   1.1  christos #define GNU_WRAPPER_SECTS "__wrapper_sects"
    183   1.1  christos #define GNU_WRAPPER_INDEX "__wrapper_index"
    184   1.1  christos #define GNU_WRAPPER_NAMES "__wrapper_names"
    185   1.1  christos 
    186   1.1  christos /* Private data for an simple_object_read.  */
    187   1.1  christos 
    188   1.1  christos struct simple_object_mach_o_read
    189   1.1  christos {
    190   1.1  christos   /* User specified segment name.  */
    191   1.1  christos   char *segment_name;
    192   1.1  christos   /* Magic number.  */
    193   1.1  christos   unsigned int magic;
    194   1.1  christos   /* Whether this file is big-endian.  */
    195   1.1  christos   int is_big_endian;
    196   1.1  christos   /* CPU type from header.  */
    197   1.1  christos   unsigned int cputype;
    198   1.1  christos   /* CPU subtype from header.  */
    199   1.1  christos   unsigned int cpusubtype;
    200   1.1  christos   /* Number of commands, from header.  */
    201   1.1  christos   unsigned int ncmds;
    202   1.1  christos   /* Flags from header.  */
    203   1.1  christos   unsigned int flags;
    204   1.1  christos   /* Reserved field from header, only used on 64-bit.  */
    205   1.1  christos   unsigned int reserved;
    206   1.1  christos };
    207   1.1  christos 
    208   1.1  christos /* Private data for an simple_object_attributes.  */
    209   1.1  christos 
    210   1.1  christos struct simple_object_mach_o_attributes
    211   1.1  christos {
    212   1.1  christos   /* Magic number.  */
    213   1.1  christos   unsigned int magic;
    214   1.1  christos   /* Whether this file is big-endian.  */
    215   1.1  christos   int is_big_endian;
    216   1.1  christos   /* CPU type from header.  */
    217   1.1  christos   unsigned int cputype;
    218   1.1  christos   /* CPU subtype from header.  */
    219   1.1  christos   unsigned int cpusubtype;
    220   1.1  christos   /* Flags from header.  */
    221   1.1  christos   unsigned int flags;
    222   1.1  christos   /* Reserved field from header, only used on 64-bit.  */
    223   1.1  christos   unsigned int reserved;
    224   1.1  christos };
    225   1.1  christos 
    226   1.1  christos /* See if we have a Mach-O MH_OBJECT file:
    227   1.1  christos 
    228   1.1  christos    A standard MH_OBJECT (from as) will have three load commands:
    229   1.1  christos    0 - LC_SEGMENT/LC_SEGMENT64
    230   1.1  christos    1 - LC_SYMTAB
    231   1.1  christos    2 - LC_DYSYMTAB
    232   1.1  christos 
    233   1.1  christos    The LC_SEGMENT/LC_SEGMENT64 will introduce a single anonymous segment
    234   1.1  christos    containing all the sections.
    235   1.1  christos 
    236   1.1  christos    Files written by simple-object will have only the segment command
    237   1.1  christos    (no symbol tables).  */
    238   1.1  christos 
    239   1.1  christos static void *
    240   1.1  christos simple_object_mach_o_match (
    241   1.1  christos     unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN],
    242   1.1  christos     int descriptor,
    243   1.1  christos     off_t offset,
    244   1.1  christos     const char *segment_name,
    245   1.1  christos     const char **errmsg,
    246   1.1  christos     int *err)
    247   1.1  christos {
    248   1.1  christos   unsigned int magic;
    249   1.1  christos   int is_big_endian;
    250   1.1  christos   unsigned int (*fetch_32) (const unsigned char *);
    251   1.1  christos   unsigned int filetype;
    252   1.1  christos   struct simple_object_mach_o_read *omr;
    253   1.1  christos   unsigned char buf[sizeof (struct mach_o_header_64)];
    254   1.1  christos   unsigned char *b;
    255   1.1  christos 
    256   1.1  christos   magic = simple_object_fetch_big_32 (header);
    257   1.1  christos   if (magic == MACH_O_MH_MAGIC || magic == MACH_O_MH_MAGIC_64)
    258   1.1  christos     is_big_endian = 1;
    259   1.1  christos   else
    260   1.1  christos     {
    261   1.1  christos       magic = simple_object_fetch_little_32 (header);
    262   1.1  christos       if (magic == MACH_O_MH_MAGIC || magic == MACH_O_MH_MAGIC_64)
    263   1.1  christos 	is_big_endian = 0;
    264   1.1  christos       else
    265   1.1  christos 	{
    266   1.1  christos 	  *errmsg = NULL;
    267   1.1  christos 	  *err = 0;
    268   1.1  christos 	  return NULL;
    269   1.1  christos 	}
    270   1.1  christos     }
    271   1.1  christos 
    272   1.1  christos #ifndef UNSIGNED_64BIT_TYPE
    273   1.1  christos   if (magic == MACH_O_MH_MAGIC_64)
    274   1.1  christos     {
    275   1.1  christos       *errmsg = "64-bit Mach-O objects not supported";
    276   1.1  christos       *err = 0;
    277   1.1  christos       return NULL;
    278   1.1  christos     }
    279   1.1  christos #endif
    280   1.1  christos 
    281   1.1  christos   /* We require the user to provide a segment name.  This is
    282   1.1  christos      unfortunate but I don't see any good choices here.  */
    283   1.1  christos 
    284   1.1  christos   if (segment_name == NULL)
    285   1.1  christos     {
    286   1.1  christos       *errmsg = "Mach-O file found but no segment name specified";
    287   1.1  christos       *err = 0;
    288   1.1  christos       return NULL;
    289   1.1  christos     }
    290   1.1  christos 
    291   1.1  christos   if (strlen (segment_name) > MACH_O_NAME_LEN)
    292   1.1  christos     {
    293   1.1  christos       *errmsg = "Mach-O segment name too long";
    294   1.1  christos       *err = 0;
    295   1.1  christos       return NULL;
    296   1.1  christos     }
    297   1.1  christos 
    298   1.1  christos   /* The 32-bit and 64-bit headers are similar enough that we can use
    299   1.1  christos      the same code.  */
    300   1.1  christos 
    301   1.1  christos   fetch_32 = (is_big_endian
    302   1.1  christos 	      ? simple_object_fetch_big_32
    303   1.1  christos 	      : simple_object_fetch_little_32);
    304   1.1  christos 
    305   1.1  christos   if (!simple_object_internal_read (descriptor, offset, buf,
    306   1.1  christos 				    (magic == MACH_O_MH_MAGIC
    307   1.1  christos 				     ? sizeof (struct mach_o_header_32)
    308   1.1  christos 				     : sizeof (struct mach_o_header_64)),
    309   1.1  christos 				    errmsg, err))
    310   1.1  christos     return NULL;
    311   1.1  christos 
    312   1.1  christos   b = &buf[0];
    313   1.1  christos 
    314   1.1  christos   filetype = (*fetch_32) (b + offsetof (struct mach_o_header_32, filetype));
    315   1.1  christos   if (filetype != MACH_O_MH_OBJECT)
    316   1.1  christos     {
    317   1.1  christos       *errmsg = "Mach-O file is not object file";
    318   1.1  christos       *err = 0;
    319   1.1  christos       return NULL;
    320   1.1  christos     }
    321   1.1  christos 
    322   1.1  christos   omr = XNEW (struct simple_object_mach_o_read);
    323   1.1  christos   omr->segment_name = xstrdup (segment_name);
    324   1.1  christos   omr->magic = magic;
    325   1.1  christos   omr->is_big_endian = is_big_endian;
    326   1.1  christos   omr->cputype = (*fetch_32) (b + offsetof (struct mach_o_header_32, cputype));
    327   1.1  christos   omr->cpusubtype = (*fetch_32) (b
    328   1.1  christos 				 + offsetof (struct mach_o_header_32,
    329   1.1  christos 					     cpusubtype));
    330   1.1  christos   omr->ncmds = (*fetch_32) (b + offsetof (struct mach_o_header_32, ncmds));
    331   1.1  christos   omr->flags = (*fetch_32) (b + offsetof (struct mach_o_header_32, flags));
    332   1.1  christos   if (magic == MACH_O_MH_MAGIC)
    333   1.1  christos     omr->reserved = 0;
    334   1.1  christos   else
    335   1.1  christos     omr->reserved = (*fetch_32) (b
    336   1.1  christos 				 + offsetof (struct mach_o_header_64,
    337   1.1  christos 					     reserved));
    338   1.1  christos 
    339   1.1  christos   return (void *) omr;
    340   1.1  christos }
    341   1.1  christos 
    342   1.1  christos /* Get the file offset and size from a section header.  */
    343   1.1  christos 
    344   1.1  christos static void
    345   1.1  christos simple_object_mach_o_section_info (int is_big_endian, int is_32,
    346   1.1  christos 				   const unsigned char *sechdr, off_t *offset,
    347   1.1  christos 				   size_t *size)
    348   1.1  christos {
    349   1.1  christos   unsigned int (*fetch_32) (const unsigned char *);
    350   1.1  christos   ulong_type (*fetch_64) (const unsigned char *);
    351   1.1  christos 
    352   1.1  christos   fetch_32 = (is_big_endian
    353   1.1  christos 	      ? simple_object_fetch_big_32
    354   1.1  christos 	      : simple_object_fetch_little_32);
    355   1.1  christos 
    356   1.1  christos   fetch_64 = NULL;
    357   1.1  christos #ifdef UNSIGNED_64BIT_TYPE
    358   1.1  christos   fetch_64 = (is_big_endian
    359   1.1  christos 	      ? simple_object_fetch_big_64
    360   1.1  christos 	      : simple_object_fetch_little_64);
    361   1.1  christos #endif
    362   1.1  christos 
    363   1.1  christos   if (is_32)
    364   1.1  christos     {
    365   1.1  christos       *offset = fetch_32 (sechdr
    366   1.1  christos 			  + offsetof (struct mach_o_section_32, offset));
    367   1.1  christos       *size = fetch_32 (sechdr
    368   1.1  christos 			+ offsetof (struct mach_o_section_32, size));
    369   1.1  christos     }
    370   1.1  christos   else
    371   1.1  christos     {
    372   1.1  christos       *offset = fetch_32 (sechdr
    373   1.1  christos 			  + offsetof (struct mach_o_section_64, offset));
    374   1.1  christos       *size = fetch_64 (sechdr
    375   1.1  christos 			+ offsetof (struct mach_o_section_64, size));
    376   1.1  christos     }
    377   1.1  christos }
    378   1.1  christos 
    379   1.1  christos /* Handle a segment in a Mach-O Object file.
    380   1.1  christos 
    381   1.1  christos    This will callback to the function pfn for each "section found" the meaning
    382   1.1  christos    of which depends on gnu extensions to mach-o:
    383   1.1  christos 
    384   1.1  christos    If we find mach-o sections (with the segment name as specified) which also
    385   1.1  christos    contain: a 'sects' wrapper, an index, and a  name table, we expand this into
    386   1.1  christos    as many sections as are specified in the index.  In this case, there will
    387   1.1  christos    be a callback for each of these.
    388   1.1  christos 
    389   1.1  christos    We will also allow an extension that permits long names (more than 16
    390   1.1  christos    characters) to be used with mach-o.  In this case, the section name has
    391   1.1  christos    a specific format embedding an index into a name table, and the file must
    392   1.1  christos    contain such name table.
    393   1.1  christos 
    394   1.1  christos    Return 1 if we should continue, 0 if the caller should return.  */
    395   1.1  christos 
    396   1.1  christos #define SOMO_SECTS_PRESENT 0x01
    397   1.1  christos #define SOMO_INDEX_PRESENT 0x02
    398   1.1  christos #define SOMO_NAMES_PRESENT 0x04
    399   1.1  christos #define SOMO_LONGN_PRESENT 0x08
    400   1.1  christos #define SOMO_WRAPPING (SOMO_SECTS_PRESENT | SOMO_INDEX_PRESENT \
    401   1.1  christos 		       | SOMO_NAMES_PRESENT)
    402   1.1  christos 
    403   1.1  christos static int
    404   1.1  christos simple_object_mach_o_segment (simple_object_read *sobj, off_t offset,
    405   1.1  christos 			      const unsigned char *segbuf,
    406   1.1  christos 			      int (*pfn) (void *, const char *, off_t offset,
    407   1.1  christos 					  off_t length),
    408   1.1  christos 			      void *data,
    409   1.1  christos 			      const char **errmsg, int *err)
    410   1.1  christos {
    411   1.1  christos   struct simple_object_mach_o_read *omr =
    412   1.1  christos     (struct simple_object_mach_o_read *) sobj->data;
    413   1.1  christos   unsigned int (*fetch_32) (const unsigned char *);
    414   1.1  christos   int is_32;
    415   1.1  christos   size_t seghdrsize;
    416   1.1  christos   size_t sechdrsize;
    417   1.1  christos   size_t segname_offset;
    418   1.1  christos   size_t sectname_offset;
    419   1.1  christos   unsigned int nsects;
    420   1.1  christos   unsigned char *secdata;
    421   1.1  christos   unsigned int i;
    422   1.1  christos   unsigned int gnu_sections_found;
    423   1.1  christos   unsigned int strtab_index;
    424   1.1  christos   unsigned int index_index;
    425   1.1  christos   unsigned int nametab_index;
    426   1.1  christos   unsigned int sections_index;
    427   1.1  christos   char *strtab;
    428   1.1  christos   char *nametab;
    429   1.1  christos   unsigned char *index;
    430   1.1  christos   size_t strtab_size;
    431   1.1  christos   size_t nametab_size;
    432   1.1  christos   size_t index_size;
    433   1.1  christos   unsigned int n_wrapped_sects;
    434   1.1  christos   size_t wrapper_sect_size;
    435   1.3  christos   off_t wrapper_sect_offset = 0;
    436   1.1  christos 
    437   1.1  christos   fetch_32 = (omr->is_big_endian
    438   1.1  christos 	      ? simple_object_fetch_big_32
    439   1.1  christos 	      : simple_object_fetch_little_32);
    440   1.1  christos 
    441   1.1  christos   is_32 = omr->magic == MACH_O_MH_MAGIC;
    442   1.1  christos 
    443   1.1  christos   if (is_32)
    444   1.1  christos     {
    445   1.1  christos       seghdrsize = sizeof (struct mach_o_segment_command_32);
    446   1.1  christos       sechdrsize = sizeof (struct mach_o_section_32);
    447   1.1  christos       segname_offset = offsetof (struct mach_o_section_32, segname);
    448   1.1  christos       sectname_offset = offsetof (struct mach_o_section_32, sectname);
    449   1.1  christos       nsects = (*fetch_32) (segbuf
    450   1.1  christos 			    + offsetof (struct mach_o_segment_command_32,
    451   1.1  christos 					nsects));
    452   1.1  christos     }
    453   1.1  christos   else
    454   1.1  christos     {
    455   1.1  christos       seghdrsize = sizeof (struct mach_o_segment_command_64);
    456   1.1  christos       sechdrsize = sizeof (struct mach_o_section_64);
    457   1.1  christos       segname_offset = offsetof (struct mach_o_section_64, segname);
    458   1.1  christos       sectname_offset = offsetof (struct mach_o_section_64, sectname);
    459   1.1  christos       nsects = (*fetch_32) (segbuf
    460   1.1  christos 			    + offsetof (struct mach_o_segment_command_64,
    461   1.1  christos 					nsects));
    462   1.1  christos     }
    463   1.1  christos 
    464   1.1  christos   /* Fetch the section headers from the segment command.  */
    465   1.1  christos 
    466   1.1  christos   secdata = XNEWVEC (unsigned char, nsects * sechdrsize);
    467   1.1  christos   if (!simple_object_internal_read (sobj->descriptor, offset + seghdrsize,
    468   1.1  christos 				    secdata, nsects * sechdrsize, errmsg, err))
    469   1.1  christos     {
    470   1.1  christos       XDELETEVEC (secdata);
    471   1.1  christos       return 0;
    472   1.1  christos     }
    473   1.1  christos 
    474   1.1  christos   /* Scan for special sections that signal GNU extensions to the format.  */
    475   1.1  christos 
    476   1.1  christos   gnu_sections_found = 0;
    477   1.1  christos   index_index = nsects;
    478   1.1  christos   sections_index = nsects;
    479   1.1  christos   strtab_index = nsects;
    480   1.1  christos   nametab_index = nsects;
    481   1.1  christos   for (i = 0; i < nsects; ++i)
    482   1.1  christos     {
    483   1.1  christos       size_t nameoff;
    484   1.1  christos 
    485   1.1  christos       nameoff = i * sechdrsize + segname_offset;
    486   1.1  christos       if (strcmp ((char *) secdata + nameoff, omr->segment_name) != 0)
    487   1.1  christos 	continue;
    488   1.1  christos 
    489   1.1  christos       nameoff = i * sechdrsize + sectname_offset;
    490   1.1  christos       if (strcmp ((char *) secdata + nameoff, GNU_WRAPPER_NAMES) == 0)
    491   1.1  christos 	{
    492   1.1  christos 	  nametab_index = i;
    493   1.1  christos 	  gnu_sections_found |= SOMO_NAMES_PRESENT;
    494   1.1  christos 	}
    495   1.1  christos       else if (strcmp ((char *) secdata + nameoff, GNU_WRAPPER_INDEX) == 0)
    496   1.1  christos 	{
    497   1.1  christos 	  index_index = i;
    498   1.1  christos 	  gnu_sections_found |= SOMO_INDEX_PRESENT;
    499   1.1  christos 	}
    500   1.1  christos       else if (strcmp ((char *) secdata + nameoff, GNU_WRAPPER_SECTS) == 0)
    501   1.1  christos 	{
    502   1.1  christos 	  sections_index = i;
    503   1.1  christos 	  gnu_sections_found |= SOMO_SECTS_PRESENT;
    504   1.1  christos 	}
    505   1.1  christos       else if (strcmp ((char *) secdata + nameoff, GNU_SECTION_NAMES) == 0)
    506   1.1  christos 	{
    507   1.1  christos 	  strtab_index = i;
    508   1.1  christos 	  gnu_sections_found |= SOMO_LONGN_PRESENT;
    509   1.1  christos 	}
    510   1.1  christos     }
    511   1.1  christos 
    512   1.1  christos   /* If any of the special wrapper section components is present, then
    513   1.1  christos      they all should be.  */
    514   1.1  christos 
    515   1.1  christos   if ((gnu_sections_found & SOMO_WRAPPING) != 0)
    516   1.1  christos     {
    517   1.1  christos       off_t nametab_offset;
    518   1.1  christos       off_t index_offset;
    519   1.1  christos 
    520   1.1  christos       if ((gnu_sections_found & SOMO_WRAPPING) != SOMO_WRAPPING)
    521   1.1  christos 	{
    522   1.1  christos 	  *errmsg = "GNU Mach-o section wrapper: required section missing";
    523   1.1  christos 	  *err = 0; /* No useful errno.  */
    524   1.1  christos 	  XDELETEVEC (secdata);
    525   1.1  christos 	  return 0;
    526   1.1  christos 	}
    527   1.1  christos 
    528   1.1  christos       /* Fetch the name table.  */
    529   1.1  christos 
    530   1.1  christos       simple_object_mach_o_section_info (omr->is_big_endian, is_32,
    531   1.1  christos 					 secdata + nametab_index * sechdrsize,
    532   1.1  christos 					 &nametab_offset, &nametab_size);
    533   1.1  christos       nametab = XNEWVEC (char, nametab_size);
    534   1.1  christos       if (!simple_object_internal_read (sobj->descriptor,
    535   1.1  christos 					sobj->offset + nametab_offset,
    536   1.1  christos 					(unsigned char *) nametab, nametab_size,
    537   1.1  christos 					errmsg, err))
    538   1.1  christos 	{
    539   1.1  christos 	  XDELETEVEC (nametab);
    540   1.1  christos 	  XDELETEVEC (secdata);
    541   1.1  christos 	  return 0;
    542   1.1  christos 	}
    543   1.1  christos 
    544   1.1  christos       /* Fetch the index.  */
    545   1.1  christos 
    546   1.1  christos       simple_object_mach_o_section_info (omr->is_big_endian, is_32,
    547   1.1  christos 					 secdata + index_index * sechdrsize,
    548   1.1  christos 					 &index_offset, &index_size);
    549   1.1  christos       index = XNEWVEC (unsigned char, index_size);
    550   1.1  christos       if (!simple_object_internal_read (sobj->descriptor,
    551   1.1  christos 					sobj->offset + index_offset,
    552   1.1  christos 					index, index_size,
    553   1.1  christos 					errmsg, err))
    554   1.1  christos 	{
    555   1.1  christos 	  XDELETEVEC (index);
    556   1.1  christos 	  XDELETEVEC (nametab);
    557   1.1  christos 	  XDELETEVEC (secdata);
    558   1.1  christos 	  return 0;
    559   1.1  christos 	}
    560   1.1  christos 
    561   1.1  christos       /* The index contains 4 unsigned ints per sub-section:
    562   1.1  christos 	 sub-section offset/length, sub-section name/length.
    563   1.1  christos 	 We fix this for both 32 and 64 bit mach-o for now, since
    564   1.1  christos 	 other fields limit the maximum size of an object to 4G.  */
    565   1.1  christos       n_wrapped_sects = index_size / 16;
    566   1.1  christos 
    567   1.1  christos       /* Get the parameters for the wrapper too.  */
    568   1.1  christos       simple_object_mach_o_section_info (omr->is_big_endian, is_32,
    569   1.1  christos 					 secdata + sections_index * sechdrsize,
    570   1.1  christos 					 &wrapper_sect_offset,
    571   1.1  christos 					 &wrapper_sect_size);
    572   1.1  christos     }
    573   1.1  christos   else
    574   1.1  christos     {
    575   1.1  christos       index = NULL;
    576   1.1  christos       index_size = 0;
    577   1.1  christos       nametab = NULL;
    578   1.1  christos       nametab_size = 0;
    579   1.1  christos       n_wrapped_sects = 0;
    580   1.1  christos     }
    581   1.1  christos 
    582   1.1  christos   /* If we have a long names section, fetch it.  */
    583   1.1  christos 
    584   1.1  christos   if ((gnu_sections_found & SOMO_LONGN_PRESENT) != 0)
    585   1.1  christos     {
    586   1.1  christos       off_t strtab_offset;
    587   1.1  christos 
    588   1.1  christos       simple_object_mach_o_section_info (omr->is_big_endian, is_32,
    589   1.1  christos 					 secdata + strtab_index * sechdrsize,
    590   1.1  christos 					 &strtab_offset, &strtab_size);
    591   1.1  christos       strtab = XNEWVEC (char, strtab_size);
    592   1.1  christos       if (!simple_object_internal_read (sobj->descriptor,
    593   1.1  christos 					sobj->offset + strtab_offset,
    594   1.1  christos 					(unsigned char *) strtab, strtab_size,
    595   1.1  christos 					errmsg, err))
    596   1.1  christos 	{
    597   1.1  christos 	  XDELETEVEC (strtab);
    598   1.1  christos 	  XDELETEVEC (index);
    599   1.1  christos 	  XDELETEVEC (nametab);
    600   1.1  christos 	  XDELETEVEC (secdata);
    601   1.1  christos 	  return 0;
    602   1.1  christos 	}
    603   1.1  christos     }
    604   1.1  christos   else
    605   1.1  christos     {
    606   1.1  christos       strtab = NULL;
    607   1.1  christos       strtab_size = 0;
    608   1.1  christos       strtab_index = nsects;
    609   1.1  christos     }
    610   1.1  christos 
    611   1.1  christos   /* Process the sections.  */
    612   1.1  christos 
    613   1.1  christos   for (i = 0; i < nsects; ++i)
    614   1.1  christos     {
    615   1.1  christos       const unsigned char *sechdr;
    616   1.1  christos       char namebuf[MACH_O_NAME_LEN * 2 + 2];
    617   1.1  christos       char *name;
    618   1.1  christos       off_t secoffset;
    619   1.1  christos       size_t secsize;
    620   1.1  christos       int l;
    621   1.1  christos 
    622   1.1  christos       sechdr = secdata + i * sechdrsize;
    623   1.1  christos 
    624   1.1  christos       /* We've already processed the long section names.  */
    625   1.1  christos 
    626   1.1  christos       if ((gnu_sections_found & SOMO_LONGN_PRESENT) != 0
    627   1.1  christos 	  && i == strtab_index)
    628   1.1  christos 	continue;
    629   1.1  christos 
    630   1.1  christos       /* We only act on the segment named.  */
    631   1.1  christos 
    632   1.1  christos       if (strcmp ((char *) sechdr + segname_offset, omr->segment_name) != 0)
    633   1.1  christos 	continue;
    634   1.1  christos 
    635   1.1  christos       /* Process sections associated with the wrapper.  */
    636   1.1  christos 
    637   1.1  christos       if ((gnu_sections_found & SOMO_WRAPPING) != 0)
    638   1.1  christos 	{
    639   1.1  christos 	  if (i == nametab_index || i == index_index)
    640   1.1  christos 	    continue;
    641   1.1  christos 
    642   1.1  christos 	  if (i == sections_index)
    643   1.1  christos 	    {
    644   1.1  christos 	      unsigned int j;
    645   1.1  christos 	      for (j = 0; j < n_wrapped_sects; ++j)
    646   1.1  christos 		{
    647   1.1  christos 		  unsigned int subsect_offset, subsect_length, name_offset;
    648   1.1  christos 		  subsect_offset = (*fetch_32) (index + 16 * j);
    649   1.1  christos 		  subsect_length = (*fetch_32) (index + 16 * j + 4);
    650   1.1  christos 		  name_offset = (*fetch_32) (index + 16 * j + 8);
    651   1.1  christos 		  /* We don't need the name_length yet.  */
    652   1.1  christos 
    653   1.1  christos 		  secoffset = wrapper_sect_offset + subsect_offset;
    654   1.1  christos 		  secsize = subsect_length;
    655   1.1  christos 		  name = nametab + name_offset;
    656   1.1  christos 
    657   1.1  christos 		  if (!(*pfn) (data, name, secoffset, secsize))
    658   1.1  christos 		    {
    659   1.1  christos 		      *errmsg = NULL;
    660   1.1  christos 		      *err = 0;
    661   1.1  christos 		      XDELETEVEC (index);
    662   1.1  christos 		      XDELETEVEC (nametab);
    663   1.1  christos 		      XDELETEVEC (strtab);
    664   1.1  christos 		      XDELETEVEC (secdata);
    665   1.1  christos 		      return 0;
    666   1.1  christos 		    }
    667   1.1  christos 		}
    668   1.1  christos 	      continue;
    669   1.1  christos 	    }
    670   1.1  christos 	}
    671   1.1  christos 
    672   1.1  christos       if ((gnu_sections_found & SOMO_LONGN_PRESENT) != 0)
    673   1.1  christos 	{
    674   1.1  christos 	  memcpy (namebuf, sechdr + sectname_offset, MACH_O_NAME_LEN);
    675   1.1  christos 	  namebuf[MACH_O_NAME_LEN] = '\0';
    676   1.1  christos 
    677   1.1  christos 	  name = &namebuf[0];
    678   1.1  christos 	  if (strtab != NULL && name[0] == '_' && name[1] == '_')
    679   1.1  christos 	    {
    680   1.1  christos 	      unsigned long stringoffset;
    681   1.1  christos 
    682   1.1  christos 	      if (sscanf (name + 2, "%08lX", &stringoffset) == 1)
    683   1.1  christos 		{
    684   1.1  christos 		  if (stringoffset >= strtab_size)
    685   1.1  christos 		    {
    686   1.1  christos 		      *errmsg = "section name offset out of range";
    687   1.1  christos 		      *err = 0;
    688   1.1  christos 		      XDELETEVEC (index);
    689   1.1  christos 		      XDELETEVEC (nametab);
    690   1.1  christos 		      XDELETEVEC (strtab);
    691   1.1  christos 		      XDELETEVEC (secdata);
    692   1.1  christos 		      return 0;
    693   1.1  christos 		    }
    694   1.1  christos 
    695   1.1  christos 		  name = strtab + stringoffset;
    696   1.1  christos 		}
    697   1.1  christos 	  }
    698   1.1  christos 	}
    699   1.1  christos       else
    700   1.1  christos 	{
    701   1.1  christos 	   /* Otherwise, make a name like __segment,__section as per the
    702   1.1  christos 	      convention in mach-o asm.  */
    703   1.1  christos 	  name = &namebuf[0];
    704   1.1  christos 	  memcpy (namebuf, (char *) sechdr + segname_offset, MACH_O_NAME_LEN);
    705   1.3  christos 	  namebuf[MACH_O_NAME_LEN] = '\0';
    706   1.1  christos 	  l = strlen (namebuf);
    707   1.1  christos 	  namebuf[l] = ',';
    708   1.1  christos 	  memcpy (namebuf + l + 1, (char *) sechdr + sectname_offset,
    709   1.1  christos 		  MACH_O_NAME_LEN);
    710   1.3  christos 	  namebuf[l + 1 + MACH_O_NAME_LEN] = '\0';
    711   1.1  christos 	}
    712   1.1  christos 
    713   1.1  christos       simple_object_mach_o_section_info (omr->is_big_endian, is_32, sechdr,
    714   1.1  christos 					 &secoffset, &secsize);
    715   1.1  christos 
    716   1.1  christos       if (!(*pfn) (data, name, secoffset, secsize))
    717   1.1  christos 	{
    718   1.1  christos 	  *errmsg = NULL;
    719   1.1  christos 	  *err = 0;
    720   1.1  christos 	  XDELETEVEC (index);
    721   1.1  christos 	  XDELETEVEC (nametab);
    722   1.1  christos 	  XDELETEVEC (strtab);
    723   1.1  christos 	  XDELETEVEC (secdata);
    724   1.1  christos 	  return 0;
    725   1.1  christos 	}
    726   1.1  christos     }
    727   1.1  christos 
    728   1.1  christos   XDELETEVEC (index);
    729   1.1  christos   XDELETEVEC (nametab);
    730   1.1  christos   XDELETEVEC (strtab);
    731   1.1  christos   XDELETEVEC (secdata);
    732   1.1  christos 
    733   1.1  christos   return 1;
    734   1.1  christos }
    735   1.1  christos 
    736   1.1  christos /* Find all sections in a Mach-O file.  */
    737   1.1  christos 
    738   1.1  christos static const char *
    739   1.1  christos simple_object_mach_o_find_sections (simple_object_read *sobj,
    740   1.1  christos 				    int (*pfn) (void *, const char *,
    741   1.1  christos 						off_t offset, off_t length),
    742   1.1  christos 				    void *data,
    743   1.1  christos 				    int *err)
    744   1.1  christos {
    745   1.1  christos   struct simple_object_mach_o_read *omr =
    746   1.1  christos     (struct simple_object_mach_o_read *) sobj->data;
    747   1.1  christos   off_t offset;
    748   1.1  christos   size_t seghdrsize;
    749   1.1  christos   unsigned int (*fetch_32) (const unsigned char *);
    750   1.1  christos   const char *errmsg;
    751   1.1  christos   unsigned int i;
    752   1.1  christos 
    753   1.1  christos   if (omr->magic == MACH_O_MH_MAGIC)
    754   1.1  christos     {
    755   1.1  christos       offset = sizeof (struct mach_o_header_32);
    756   1.1  christos       seghdrsize = sizeof (struct mach_o_segment_command_32);
    757   1.1  christos     }
    758   1.1  christos   else
    759   1.1  christos     {
    760   1.1  christos       offset = sizeof (struct mach_o_header_64);
    761   1.1  christos       seghdrsize = sizeof (struct mach_o_segment_command_64);
    762   1.1  christos     }
    763   1.1  christos 
    764   1.1  christos   fetch_32 = (omr->is_big_endian
    765   1.1  christos 	      ? simple_object_fetch_big_32
    766   1.1  christos 	      : simple_object_fetch_little_32);
    767   1.1  christos 
    768   1.1  christos   for (i = 0; i < omr->ncmds; ++i)
    769   1.1  christos     {
    770   1.1  christos       unsigned char loadbuf[sizeof (struct mach_o_load_command)];
    771   1.1  christos       unsigned int cmd;
    772   1.1  christos       unsigned int cmdsize;
    773   1.1  christos 
    774   1.1  christos       if (!simple_object_internal_read (sobj->descriptor,
    775   1.1  christos 					sobj->offset + offset,
    776   1.1  christos 					loadbuf,
    777   1.1  christos 					sizeof (struct mach_o_load_command),
    778   1.1  christos 					&errmsg, err))
    779   1.1  christos 	return errmsg;
    780   1.1  christos 
    781   1.1  christos       cmd = (*fetch_32) (loadbuf + offsetof (struct mach_o_load_command, cmd));
    782   1.1  christos       cmdsize = (*fetch_32) (loadbuf
    783   1.1  christos 			     + offsetof (struct mach_o_load_command, cmdsize));
    784   1.1  christos 
    785   1.1  christos       if (cmd == MACH_O_LC_SEGMENT || cmd == MACH_O_LC_SEGMENT_64)
    786   1.1  christos 	{
    787   1.1  christos 	  unsigned char segbuf[sizeof (struct mach_o_segment_command_64)];
    788   1.1  christos 	  int r;
    789   1.1  christos 
    790   1.1  christos 	  if (!simple_object_internal_read (sobj->descriptor,
    791   1.1  christos 					    sobj->offset + offset,
    792   1.1  christos 					    segbuf, seghdrsize, &errmsg, err))
    793   1.1  christos 	    return errmsg;
    794   1.1  christos 
    795   1.1  christos 	  r = simple_object_mach_o_segment (sobj, offset, segbuf, pfn,
    796   1.1  christos 					    data, &errmsg, err);
    797   1.1  christos 	  if (!r)
    798   1.1  christos 	    return errmsg;
    799   1.1  christos 	}
    800   1.1  christos 
    801   1.1  christos       offset += cmdsize;
    802   1.1  christos     }
    803   1.1  christos 
    804   1.1  christos   return NULL;
    805   1.1  christos }
    806   1.1  christos 
    807   1.1  christos /* Fetch the attributes for an simple_object_read.  */
    808   1.1  christos 
    809   1.1  christos static void *
    810   1.1  christos simple_object_mach_o_fetch_attributes (simple_object_read *sobj,
    811   1.1  christos 				       const char **errmsg ATTRIBUTE_UNUSED,
    812   1.1  christos 				       int *err ATTRIBUTE_UNUSED)
    813   1.1  christos {
    814   1.1  christos   struct simple_object_mach_o_read *omr =
    815   1.1  christos     (struct simple_object_mach_o_read *) sobj->data;
    816   1.1  christos   struct simple_object_mach_o_attributes *ret;
    817   1.1  christos 
    818   1.1  christos   ret = XNEW (struct simple_object_mach_o_attributes);
    819   1.1  christos   ret->magic = omr->magic;
    820   1.1  christos   ret->is_big_endian = omr->is_big_endian;
    821   1.1  christos   ret->cputype = omr->cputype;
    822   1.1  christos   ret->cpusubtype = omr->cpusubtype;
    823   1.1  christos   ret->flags = omr->flags;
    824   1.1  christos   ret->reserved = omr->reserved;
    825   1.1  christos   return ret;
    826   1.1  christos }
    827   1.1  christos 
    828   1.1  christos /* Release the private data for an simple_object_read.  */
    829   1.1  christos 
    830   1.1  christos static void
    831   1.1  christos simple_object_mach_o_release_read (void *data)
    832   1.1  christos {
    833   1.1  christos   struct simple_object_mach_o_read *omr =
    834   1.1  christos     (struct simple_object_mach_o_read *) data;
    835   1.1  christos 
    836   1.1  christos   free (omr->segment_name);
    837   1.1  christos   XDELETE (omr);
    838   1.1  christos }
    839   1.1  christos 
    840   1.1  christos /* Compare two attributes structures.  */
    841   1.1  christos 
    842   1.1  christos static const char *
    843   1.1  christos simple_object_mach_o_attributes_merge (void *todata, void *fromdata, int *err)
    844   1.1  christos {
    845   1.1  christos   struct simple_object_mach_o_attributes *to =
    846   1.1  christos     (struct simple_object_mach_o_attributes *) todata;
    847   1.1  christos   struct simple_object_mach_o_attributes *from =
    848   1.1  christos     (struct simple_object_mach_o_attributes *) fromdata;
    849   1.1  christos 
    850   1.1  christos   if (to->magic != from->magic
    851   1.1  christos       || to->is_big_endian != from->is_big_endian
    852   1.1  christos       || to->cputype != from->cputype)
    853   1.1  christos     {
    854   1.1  christos       *err = 0;
    855   1.1  christos       return "Mach-O object format mismatch";
    856   1.1  christos     }
    857   1.1  christos   return NULL;
    858   1.1  christos }
    859   1.1  christos 
    860   1.1  christos /* Release the private data for an attributes structure.  */
    861   1.1  christos 
    862   1.1  christos static void
    863   1.1  christos simple_object_mach_o_release_attributes (void *data)
    864   1.1  christos {
    865   1.1  christos   XDELETE (data);
    866   1.1  christos }
    867   1.1  christos 
    868   1.1  christos /* Prepare to write out a file.  */
    869   1.1  christos 
    870   1.1  christos static void *
    871   1.1  christos simple_object_mach_o_start_write (void *attributes_data,
    872   1.1  christos 				  const char **errmsg ATTRIBUTE_UNUSED,
    873   1.1  christos 				  int *err ATTRIBUTE_UNUSED)
    874   1.1  christos {
    875   1.1  christos   struct simple_object_mach_o_attributes *attrs =
    876   1.1  christos     (struct simple_object_mach_o_attributes *) attributes_data;
    877   1.1  christos   struct simple_object_mach_o_attributes *ret;
    878   1.1  christos 
    879   1.1  christos   /* We're just going to record the attributes, but we need to make a
    880   1.1  christos      copy because the user may delete them.  */
    881   1.1  christos   ret = XNEW (struct simple_object_mach_o_attributes);
    882   1.1  christos   *ret = *attrs;
    883   1.1  christos   return ret;
    884   1.1  christos }
    885   1.1  christos 
    886   1.1  christos /* Write out the header of a Mach-O file.  */
    887   1.1  christos 
    888   1.1  christos static int
    889   1.1  christos simple_object_mach_o_write_header (simple_object_write *sobj, int descriptor,
    890   1.1  christos 				   size_t nsects, const char **errmsg,
    891   1.1  christos 				   int *err)
    892   1.1  christos {
    893   1.1  christos   struct simple_object_mach_o_attributes *attrs =
    894   1.1  christos     (struct simple_object_mach_o_attributes *) sobj->data;
    895   1.1  christos   void (*set_32) (unsigned char *, unsigned int);
    896   1.1  christos   unsigned char hdrbuf[sizeof (struct mach_o_header_64)];
    897   1.1  christos   unsigned char *hdr;
    898   1.1  christos   size_t wrsize;
    899   1.1  christos 
    900   1.1  christos   set_32 = (attrs->is_big_endian
    901   1.1  christos 	    ? simple_object_set_big_32
    902   1.1  christos 	    : simple_object_set_little_32);
    903   1.1  christos 
    904   1.1  christos   memset (hdrbuf, 0, sizeof hdrbuf);
    905   1.1  christos 
    906   1.1  christos   /* The 32-bit and 64-bit headers start out the same.  */
    907   1.1  christos 
    908   1.1  christos   hdr = &hdrbuf[0];
    909   1.1  christos   set_32 (hdr + offsetof (struct mach_o_header_32, magic), attrs->magic);
    910   1.1  christos   set_32 (hdr + offsetof (struct mach_o_header_32, cputype), attrs->cputype);
    911   1.1  christos   set_32 (hdr + offsetof (struct mach_o_header_32, cpusubtype),
    912   1.1  christos 	  attrs->cpusubtype);
    913   1.1  christos   set_32 (hdr + offsetof (struct mach_o_header_32, filetype), MACH_O_MH_OBJECT);
    914   1.1  christos   set_32 (hdr + offsetof (struct mach_o_header_32, ncmds), 1);
    915   1.1  christos   set_32 (hdr + offsetof (struct mach_o_header_32, flags), attrs->flags);
    916   1.1  christos   if (attrs->magic == MACH_O_MH_MAGIC)
    917   1.1  christos     {
    918   1.1  christos       wrsize = sizeof (struct mach_o_header_32);
    919   1.1  christos       set_32 (hdr + offsetof (struct mach_o_header_32, sizeofcmds),
    920   1.1  christos 	      (sizeof (struct mach_o_segment_command_32)
    921   1.1  christos 	       + nsects * sizeof (struct mach_o_section_32)));
    922   1.1  christos     }
    923   1.1  christos   else
    924   1.1  christos     {
    925   1.1  christos       set_32 (hdr + offsetof (struct mach_o_header_64, sizeofcmds),
    926   1.1  christos 	      (sizeof (struct mach_o_segment_command_64)
    927   1.1  christos 	       + nsects * sizeof (struct mach_o_section_64)));
    928   1.1  christos       set_32 (hdr + offsetof (struct mach_o_header_64, reserved),
    929   1.1  christos 	      attrs->reserved);
    930   1.1  christos       wrsize = sizeof (struct mach_o_header_64);
    931   1.1  christos     }
    932   1.1  christos 
    933   1.1  christos   return simple_object_internal_write (descriptor, 0, hdrbuf, wrsize,
    934   1.1  christos 				       errmsg, err);
    935   1.1  christos }
    936   1.1  christos 
    937   1.1  christos /* Write a Mach-O section header.  */
    938   1.1  christos 
    939   1.1  christos static int
    940   1.1  christos simple_object_mach_o_write_section_header (simple_object_write *sobj,
    941   1.1  christos 					   int descriptor,
    942   1.1  christos 					   size_t sechdr_offset,
    943   1.1  christos 					   const char *name, const char *segn,
    944   1.1  christos 					   size_t secaddr, size_t secsize,
    945   1.1  christos 					   size_t offset, unsigned int align,
    946   1.1  christos 					   const char **errmsg, int *err)
    947   1.1  christos {
    948   1.1  christos   struct simple_object_mach_o_attributes *attrs =
    949   1.1  christos     (struct simple_object_mach_o_attributes *) sobj->data;
    950   1.1  christos   void (*set_32) (unsigned char *, unsigned int);
    951   1.1  christos   unsigned char hdrbuf[sizeof (struct mach_o_section_64)];
    952   1.1  christos   unsigned char *hdr;
    953   1.1  christos   size_t sechdrsize;
    954   1.1  christos 
    955   1.1  christos   set_32 = (attrs->is_big_endian
    956   1.1  christos 	    ? simple_object_set_big_32
    957   1.1  christos 	    : simple_object_set_little_32);
    958   1.1  christos 
    959   1.1  christos   memset (hdrbuf, 0, sizeof hdrbuf);
    960   1.1  christos 
    961   1.1  christos   hdr = &hdrbuf[0];
    962   1.1  christos   if (attrs->magic == MACH_O_MH_MAGIC)
    963   1.1  christos     {
    964   1.1  christos       strncpy ((char *) hdr + offsetof (struct mach_o_section_32, sectname),
    965   1.1  christos 	       name, MACH_O_NAME_LEN);
    966   1.1  christos       strncpy ((char *) hdr + offsetof (struct mach_o_section_32, segname),
    967   1.1  christos 	       segn, MACH_O_NAME_LEN);
    968   1.1  christos       set_32 (hdr + offsetof (struct mach_o_section_32, addr), secaddr);
    969   1.1  christos       set_32 (hdr + offsetof (struct mach_o_section_32, size), secsize);
    970   1.1  christos       set_32 (hdr + offsetof (struct mach_o_section_32, offset), offset);
    971   1.1  christos       set_32 (hdr + offsetof (struct mach_o_section_32, align), align);
    972   1.1  christos       /* reloff left as zero.  */
    973   1.1  christos       /* nreloc left as zero.  */
    974   1.1  christos       set_32 (hdr + offsetof (struct mach_o_section_32, flags),
    975   1.1  christos 	      MACH_O_S_ATTR_DEBUG);
    976   1.1  christos       /* reserved1 left as zero.  */
    977   1.1  christos       /* reserved2 left as zero.  */
    978   1.1  christos       sechdrsize = sizeof (struct mach_o_section_32);
    979   1.1  christos     }
    980   1.1  christos   else
    981   1.1  christos     {
    982   1.1  christos #ifdef UNSIGNED_64BIT_TYPE
    983   1.1  christos       void (*set_64) (unsigned char *, ulong_type);
    984   1.1  christos 
    985   1.1  christos       set_64 = (attrs->is_big_endian
    986   1.1  christos 		? simple_object_set_big_64
    987   1.1  christos 		: simple_object_set_little_64);
    988   1.1  christos 
    989   1.1  christos       strncpy ((char *) hdr + offsetof (struct mach_o_section_64, sectname),
    990   1.1  christos 	       name, MACH_O_NAME_LEN);
    991   1.1  christos       strncpy ((char *) hdr + offsetof (struct mach_o_section_64, segname),
    992   1.1  christos 	       segn, MACH_O_NAME_LEN);
    993   1.1  christos       set_64 (hdr + offsetof (struct mach_o_section_64, addr), secaddr);
    994   1.1  christos       set_64 (hdr + offsetof (struct mach_o_section_64, size), secsize);
    995   1.1  christos       set_32 (hdr + offsetof (struct mach_o_section_64, offset), offset);
    996   1.1  christos       set_32 (hdr + offsetof (struct mach_o_section_64, align), align);
    997   1.1  christos       /* reloff left as zero.  */
    998   1.1  christos       /* nreloc left as zero.  */
    999   1.1  christos       set_32 (hdr + offsetof (struct mach_o_section_64, flags),
   1000   1.1  christos 	      MACH_O_S_ATTR_DEBUG);
   1001   1.1  christos       /* reserved1 left as zero.  */
   1002   1.1  christos       /* reserved2 left as zero.  */
   1003   1.1  christos       /* reserved3 left as zero.  */
   1004   1.1  christos #endif
   1005   1.1  christos       sechdrsize = sizeof (struct mach_o_section_64);
   1006   1.1  christos     }
   1007   1.1  christos 
   1008   1.1  christos   return simple_object_internal_write (descriptor, sechdr_offset, hdr,
   1009   1.1  christos 				       sechdrsize, errmsg, err);
   1010   1.1  christos }
   1011   1.1  christos 
   1012   1.1  christos /* Write out the single (anonymous) segment containing the sections of a Mach-O
   1013   1.1  christos    Object file.
   1014   1.1  christos 
   1015   1.1  christos    As a GNU extension to mach-o, when the caller specifies a segment name in
   1016   1.1  christos    sobj->segment_name, all the sections passed will be output under a single
   1017   1.1  christos    mach-o section header.  The caller's sections are indexed within this
   1018   1.1  christos    'wrapper' section by a table stored in a second mach-o section.  Finally,
   1019   1.1  christos    arbitrary length section names are permitted by the extension and these are
   1020   1.1  christos    stored in a table in a third mach-o section.
   1021   1.1  christos 
   1022   1.1  christos    Note that this is only likely to make any sense for the __GNU_LTO segment
   1023   1.1  christos    at present.
   1024   1.1  christos 
   1025   1.1  christos    If the wrapper extension is not in force, we assume that the section name
   1026   1.1  christos    is in the form __SEGMENT_NAME,__section_name as per Mach-O asm.  */
   1027   1.1  christos 
   1028   1.1  christos static int
   1029   1.1  christos simple_object_mach_o_write_segment (simple_object_write *sobj, int descriptor,
   1030   1.1  christos 				    size_t *nsects, const char **errmsg,
   1031   1.1  christos 				    int *err)
   1032   1.1  christos {
   1033   1.1  christos   struct simple_object_mach_o_attributes *attrs =
   1034   1.1  christos     (struct simple_object_mach_o_attributes *) sobj->data;
   1035   1.1  christos   void (*set_32) (unsigned char *, unsigned int);
   1036   1.1  christos   size_t hdrsize;
   1037   1.1  christos   size_t seghdrsize;
   1038   1.1  christos   size_t sechdrsize;
   1039   1.1  christos   size_t cmdsize;
   1040   1.1  christos   size_t offset;
   1041   1.1  christos   size_t sechdr_offset;
   1042   1.1  christos   size_t secaddr;
   1043   1.1  christos   unsigned int name_offset;
   1044   1.1  christos   simple_object_write_section *section;
   1045   1.1  christos   unsigned char hdrbuf[sizeof (struct mach_o_segment_command_64)];
   1046   1.1  christos   unsigned char *hdr;
   1047   1.1  christos   size_t nsects_in;
   1048   1.1  christos   unsigned int *index;
   1049   1.1  christos   char *snames;
   1050   1.1  christos   unsigned int sect;
   1051   1.1  christos 
   1052   1.1  christos   set_32 = (attrs->is_big_endian
   1053   1.1  christos 	    ? simple_object_set_big_32
   1054   1.1  christos 	    : simple_object_set_little_32);
   1055   1.1  christos 
   1056   1.1  christos   /* Write out the sections first.  */
   1057   1.1  christos 
   1058   1.1  christos   if (attrs->magic == MACH_O_MH_MAGIC)
   1059   1.1  christos     {
   1060   1.1  christos       hdrsize = sizeof (struct mach_o_header_32);
   1061   1.1  christos       seghdrsize = sizeof (struct mach_o_segment_command_32);
   1062   1.1  christos       sechdrsize = sizeof (struct mach_o_section_32);
   1063   1.1  christos     }
   1064   1.1  christos   else
   1065   1.1  christos     {
   1066   1.1  christos       hdrsize = sizeof (struct mach_o_header_64);
   1067   1.1  christos       seghdrsize = sizeof (struct mach_o_segment_command_64);
   1068   1.1  christos       sechdrsize = sizeof (struct mach_o_section_64);
   1069   1.1  christos     }
   1070   1.1  christos 
   1071   1.1  christos   name_offset = 0;
   1072   1.1  christos   *nsects = nsects_in = 0;
   1073   1.1  christos 
   1074   1.1  christos   /* Count the number of sections we start with.  */
   1075   1.1  christos 
   1076   1.1  christos   for (section = sobj->sections; section != NULL; section = section->next)
   1077   1.1  christos     nsects_in++;
   1078   1.1  christos 
   1079   1.1  christos   if (sobj->segment_name != NULL)
   1080   1.1  christos     {
   1081   1.1  christos       /* We will only write 3 sections: wrapped data, index and names.  */
   1082   1.1  christos 
   1083   1.1  christos       *nsects = 3;
   1084   1.1  christos 
   1085   1.1  christos       /* The index has four entries per wrapped section:
   1086   1.1  christos 	   Section Offset, length,  Name offset, length.
   1087   1.1  christos 	 Where the offsets are based at the start of the wrapper and name
   1088   1.1  christos 	 sections respectively.
   1089   1.1  christos 	 The values are stored as 32 bit int for both 32 and 64 bit mach-o
   1090   1.1  christos 	 since the size of a mach-o MH_OBJECT cannot exceed 4G owing to
   1091   1.1  christos 	 other constraints.  */
   1092   1.1  christos 
   1093   1.1  christos       index = XNEWVEC (unsigned int, nsects_in * 4);
   1094   1.1  christos 
   1095   1.1  christos       /* We now need to figure out the size of the names section.  This just
   1096   1.1  christos 	 stores the names as null-terminated c strings, packed without any
   1097   1.1  christos 	 alignment padding.  */
   1098   1.1  christos 
   1099   1.1  christos       for (section = sobj->sections, sect = 0; section != NULL;
   1100   1.1  christos 	   section = section->next, sect++)
   1101   1.1  christos 	{
   1102   1.1  christos 	  index[sect*4+2] = name_offset;
   1103   1.1  christos 	  index[sect*4+3] = strlen (section->name) + 1;
   1104   1.1  christos 	  name_offset += strlen (section->name) + 1;
   1105   1.1  christos 	}
   1106   1.1  christos       snames = XNEWVEC (char, name_offset);
   1107   1.1  christos     }
   1108   1.1  christos   else
   1109   1.1  christos     {
   1110   1.1  christos       *nsects = nsects_in;
   1111   1.1  christos       index = NULL;
   1112   1.1  christos       snames = NULL;
   1113   1.1  christos     }
   1114   1.1  christos 
   1115   1.1  christos   sechdr_offset = hdrsize + seghdrsize;
   1116   1.1  christos   cmdsize = seghdrsize + *nsects * sechdrsize;
   1117   1.1  christos   offset = hdrsize + cmdsize;
   1118   1.1  christos   secaddr = 0;
   1119   1.1  christos 
   1120   1.1  christos   for (section = sobj->sections, sect = 0;
   1121   1.1  christos        section != NULL; section = section->next, sect++)
   1122   1.1  christos     {
   1123   1.1  christos       size_t mask;
   1124   1.1  christos       size_t new_offset;
   1125   1.1  christos       size_t secsize;
   1126   1.1  christos       struct simple_object_write_section_buffer *buffer;
   1127   1.1  christos 
   1128   1.1  christos       mask = (1U << section->align) - 1;
   1129   1.1  christos       new_offset = offset + mask;
   1130   1.1  christos       new_offset &= ~ mask;
   1131   1.1  christos       while (new_offset > offset)
   1132   1.1  christos 	{
   1133   1.1  christos 	  unsigned char zeroes[16];
   1134   1.1  christos 	  size_t write;
   1135   1.1  christos 
   1136   1.1  christos 	  memset (zeroes, 0, sizeof zeroes);
   1137   1.1  christos 	  write = new_offset - offset;
   1138   1.1  christos 	  if (write > sizeof zeroes)
   1139   1.1  christos 	    write = sizeof zeroes;
   1140   1.1  christos 	  if (!simple_object_internal_write (descriptor, offset, zeroes, write,
   1141   1.1  christos 					     errmsg, err))
   1142   1.1  christos 	    return 0;
   1143   1.1  christos 	  offset += write;
   1144   1.1  christos 	}
   1145   1.1  christos 
   1146   1.1  christos       secsize = 0;
   1147   1.1  christos       for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
   1148   1.1  christos 	{
   1149   1.1  christos 	  if (!simple_object_internal_write (descriptor, offset + secsize,
   1150   1.1  christos 					     ((const unsigned char *)
   1151   1.1  christos 					      buffer->buffer),
   1152   1.1  christos 					     buffer->size, errmsg, err))
   1153   1.1  christos 	    return 0;
   1154   1.1  christos 	  secsize += buffer->size;
   1155   1.1  christos 	}
   1156   1.1  christos 
   1157   1.1  christos       if (sobj->segment_name != NULL)
   1158   1.1  christos 	{
   1159   1.1  christos 	  index[sect*4+0] = (unsigned int) offset;
   1160   1.1  christos 	  index[sect*4+1] = secsize;
   1161   1.1  christos 	  /* Stash the section name in our table.  */
   1162   1.1  christos 	  memcpy (snames + index[sect * 4 + 2], section->name,
   1163   1.1  christos 		  index[sect * 4 + 3]);
   1164   1.1  christos 	}
   1165   1.1  christos       else
   1166   1.1  christos 	{
   1167   1.1  christos 	  char namebuf[MACH_O_NAME_LEN + 1];
   1168   1.1  christos 	  char segnbuf[MACH_O_NAME_LEN + 1];
   1169   1.1  christos 	  char *comma;
   1170   1.1  christos 
   1171   1.1  christos 	  /* Try to extract segment,section from the input name.  */
   1172   1.1  christos 
   1173   1.1  christos 	  memset (namebuf, 0, sizeof namebuf);
   1174   1.1  christos 	  memset (segnbuf, 0, sizeof segnbuf);
   1175   1.1  christos 	  comma = strchr (section->name, ',');
   1176   1.1  christos 	  if (comma != NULL)
   1177   1.1  christos 	    {
   1178   1.1  christos 	      int len = comma - section->name;
   1179   1.1  christos 	      len = len > MACH_O_NAME_LEN ? MACH_O_NAME_LEN : len;
   1180   1.1  christos 	      strncpy (namebuf, section->name, len);
   1181   1.1  christos 	      strncpy (segnbuf, comma + 1, MACH_O_NAME_LEN);
   1182   1.1  christos 	    }
   1183   1.1  christos 	  else /* just try to copy the name, leave segment blank.  */
   1184   1.1  christos 	    strncpy (namebuf, section->name, MACH_O_NAME_LEN);
   1185   1.1  christos 
   1186   1.1  christos 	  if (!simple_object_mach_o_write_section_header (sobj, descriptor,
   1187   1.1  christos 							  sechdr_offset,
   1188   1.1  christos 							  namebuf, segnbuf,
   1189   1.1  christos 							  secaddr, secsize,
   1190   1.1  christos 							  offset,
   1191   1.1  christos 							  section->align,
   1192   1.1  christos 							  errmsg, err))
   1193   1.1  christos 	    return 0;
   1194   1.1  christos 	  sechdr_offset += sechdrsize;
   1195   1.1  christos 	}
   1196   1.1  christos 
   1197   1.1  christos       offset += secsize;
   1198   1.1  christos       secaddr += secsize;
   1199   1.1  christos     }
   1200   1.1  christos 
   1201   1.1  christos   if (sobj->segment_name != NULL)
   1202   1.1  christos     {
   1203   1.1  christos       size_t secsize;
   1204   1.1  christos       unsigned int i;
   1205   1.1  christos 
   1206   1.1  christos       /* Write the section header for the wrapper.  */
   1207   1.1  christos       /* Account for any initial aligment - which becomes the alignment for this
   1208   1.1  christos 	 created section.  */
   1209   1.1  christos 
   1210   1.1  christos       secsize = (offset - index[0]);
   1211   1.1  christos       if (!simple_object_mach_o_write_section_header (sobj, descriptor,
   1212   1.1  christos 						      sechdr_offset,
   1213   1.1  christos 						      GNU_WRAPPER_SECTS,
   1214   1.1  christos 						      sobj->segment_name,
   1215   1.1  christos 						      0 /*secaddr*/,
   1216   1.1  christos 						      secsize, index[0],
   1217   1.1  christos 						      sobj->sections->align,
   1218   1.1  christos 						      errmsg, err))
   1219   1.1  christos 	return 0;
   1220   1.1  christos 
   1221   1.1  christos       /* Subtract the wrapper section start from the begining of each sub
   1222   1.1  christos 	 section.  */
   1223   1.1  christos 
   1224   1.1  christos       for (i = 1; i < nsects_in; ++i)
   1225   1.1  christos 	index[4 * i] -= index[0];
   1226   1.1  christos       index[0] = 0;
   1227   1.1  christos 
   1228   1.8  christos       /* Swap the indices, if required.  */
   1229   1.8  christos 
   1230   1.8  christos       for (i = 0; i < (nsects_in * 4); ++i)
   1231   1.8  christos 	set_32 ((unsigned char *) &index[i], index[i]);
   1232   1.8  christos 
   1233   1.1  christos       sechdr_offset += sechdrsize;
   1234   1.1  christos 
   1235   1.1  christos       /* Write out the section names.
   1236   1.1  christos 	 ... the header ...
   1237   1.1  christos 	 name_offset contains the length of the section.  It is not aligned.  */
   1238   1.1  christos 
   1239   1.1  christos       if (!simple_object_mach_o_write_section_header (sobj, descriptor,
   1240   1.1  christos 						      sechdr_offset,
   1241   1.1  christos 						      GNU_WRAPPER_NAMES,
   1242   1.1  christos 						      sobj->segment_name,
   1243   1.1  christos 						      0 /*secaddr*/,
   1244   1.1  christos 						      name_offset,
   1245   1.1  christos 						      offset,
   1246   1.1  christos 						      0, errmsg, err))
   1247   1.1  christos 	return 0;
   1248   1.1  christos 
   1249   1.1  christos       /* ... and the content.. */
   1250   1.1  christos       if (!simple_object_internal_write (descriptor, offset,
   1251   1.1  christos 					 (const unsigned char *) snames,
   1252   1.1  christos 					 name_offset, errmsg, err))
   1253   1.1  christos 	return 0;
   1254   1.1  christos 
   1255   1.1  christos       sechdr_offset += sechdrsize;
   1256   1.1  christos       secaddr += name_offset;
   1257   1.1  christos       offset += name_offset;
   1258   1.1  christos 
   1259   1.1  christos       /* Now do the index, we'll align this to 4 bytes although the read code
   1260   1.1  christos 	 will handle unaligned.  */
   1261   1.1  christos 
   1262   1.1  christos       offset += 3;
   1263   1.1  christos       offset &= ~0x03;
   1264   1.1  christos       if (!simple_object_mach_o_write_section_header (sobj, descriptor,
   1265   1.1  christos 						      sechdr_offset,
   1266   1.1  christos 						      GNU_WRAPPER_INDEX,
   1267   1.1  christos 						      sobj->segment_name,
   1268   1.1  christos 						      0 /*secaddr*/,
   1269   1.1  christos 						      nsects_in * 16,
   1270   1.1  christos 						      offset,
   1271   1.1  christos 						      2, errmsg, err))
   1272   1.1  christos 	return 0;
   1273   1.1  christos 
   1274   1.1  christos       /* ... and the content.. */
   1275   1.1  christos       if (!simple_object_internal_write (descriptor, offset,
   1276   1.1  christos 					 (const unsigned char *) index,
   1277   1.1  christos 					 nsects_in*16, errmsg, err))
   1278   1.1  christos 	return 0;
   1279   1.1  christos 
   1280   1.1  christos       XDELETEVEC (index);
   1281   1.1  christos       XDELETEVEC (snames);
   1282   1.1  christos     }
   1283   1.1  christos 
   1284   1.1  christos   /* Write out the segment header.  */
   1285   1.1  christos 
   1286   1.1  christos   memset (hdrbuf, 0, sizeof hdrbuf);
   1287   1.1  christos 
   1288   1.1  christos   hdr = &hdrbuf[0];
   1289   1.1  christos   if (attrs->magic == MACH_O_MH_MAGIC)
   1290   1.1  christos     {
   1291   1.1  christos       set_32 (hdr + offsetof (struct mach_o_segment_command_32, cmd),
   1292   1.1  christos 	      MACH_O_LC_SEGMENT);
   1293   1.1  christos       set_32 (hdr + offsetof (struct mach_o_segment_command_32, cmdsize),
   1294   1.1  christos 	      cmdsize);
   1295   1.1  christos      /* MH_OBJECTS have a single, anonymous, segment - so the segment name
   1296   1.1  christos 	 is left empty.  */
   1297   1.1  christos       /* vmaddr left as zero.  */
   1298   1.1  christos       /* vmsize left as zero.  */
   1299   1.1  christos       set_32 (hdr + offsetof (struct mach_o_segment_command_32, fileoff),
   1300   1.1  christos 	      hdrsize + cmdsize);
   1301   1.1  christos       set_32 (hdr + offsetof (struct mach_o_segment_command_32, filesize),
   1302   1.1  christos 	      offset - (hdrsize + cmdsize));
   1303   1.1  christos       /* maxprot left as zero.  */
   1304   1.1  christos       /* initprot left as zero.  */
   1305   1.1  christos       set_32 (hdr + offsetof (struct mach_o_segment_command_32, nsects),
   1306   1.1  christos 	      *nsects);
   1307   1.1  christos       /* flags left as zero.  */
   1308   1.1  christos     }
   1309   1.1  christos   else
   1310   1.1  christos     {
   1311   1.1  christos #ifdef UNSIGNED_64BIT_TYPE
   1312   1.1  christos       void (*set_64) (unsigned char *, ulong_type);
   1313   1.1  christos 
   1314   1.1  christos       set_64 = (attrs->is_big_endian
   1315   1.1  christos 		? simple_object_set_big_64
   1316   1.1  christos 		: simple_object_set_little_64);
   1317   1.1  christos 
   1318   1.1  christos       set_32 (hdr + offsetof (struct mach_o_segment_command_64, cmd),
   1319   1.1  christos 	      MACH_O_LC_SEGMENT);
   1320   1.1  christos       set_32 (hdr + offsetof (struct mach_o_segment_command_64, cmdsize),
   1321   1.1  christos 	      cmdsize);
   1322   1.1  christos       /* MH_OBJECTS have a single, anonymous, segment - so the segment name
   1323   1.1  christos 	 is left empty.  */
   1324   1.1  christos       /* vmaddr left as zero.  */
   1325   1.1  christos       /* vmsize left as zero.  */
   1326   1.1  christos       set_64 (hdr + offsetof (struct mach_o_segment_command_64, fileoff),
   1327   1.1  christos 	      hdrsize + cmdsize);
   1328   1.1  christos       set_64 (hdr + offsetof (struct mach_o_segment_command_64, filesize),
   1329   1.1  christos 	      offset - (hdrsize + cmdsize));
   1330   1.1  christos       /* maxprot left as zero.  */
   1331   1.1  christos       /* initprot left as zero.  */
   1332   1.1  christos       set_32 (hdr + offsetof (struct mach_o_segment_command_64, nsects),
   1333   1.1  christos 	      *nsects);
   1334   1.1  christos       /* flags left as zero.  */
   1335   1.1  christos #endif
   1336   1.1  christos     }
   1337   1.1  christos 
   1338   1.1  christos   return simple_object_internal_write (descriptor, hdrsize, hdr, seghdrsize,
   1339   1.1  christos 				       errmsg, err);
   1340   1.1  christos }
   1341   1.1  christos 
   1342   1.1  christos /* Write out a complete Mach-O file.  */
   1343   1.1  christos 
   1344   1.1  christos static const char *
   1345   1.1  christos simple_object_mach_o_write_to_file (simple_object_write *sobj, int descriptor,
   1346   1.1  christos 				    int *err)
   1347   1.1  christos {
   1348   1.1  christos   size_t nsects = 0;
   1349   1.1  christos   const char *errmsg;
   1350   1.1  christos 
   1351   1.1  christos   if (!simple_object_mach_o_write_segment (sobj, descriptor, &nsects,
   1352   1.1  christos 					   &errmsg, err))
   1353   1.1  christos     return errmsg;
   1354   1.1  christos 
   1355   1.1  christos   if (!simple_object_mach_o_write_header (sobj, descriptor, nsects,
   1356   1.1  christos 					  &errmsg, err))
   1357   1.1  christos     return errmsg;
   1358   1.1  christos 
   1359   1.1  christos   return NULL;
   1360   1.1  christos }
   1361   1.1  christos 
   1362   1.1  christos /* Release the private data for an simple_object_write structure.  */
   1363   1.1  christos 
   1364   1.1  christos static void
   1365   1.1  christos simple_object_mach_o_release_write (void *data)
   1366   1.1  christos {
   1367   1.1  christos   XDELETE (data);
   1368   1.1  christos }
   1369   1.1  christos 
   1370   1.1  christos /* The Mach-O functions.  */
   1371   1.1  christos 
   1372   1.1  christos const struct simple_object_functions simple_object_mach_o_functions =
   1373   1.1  christos {
   1374   1.1  christos   simple_object_mach_o_match,
   1375   1.1  christos   simple_object_mach_o_find_sections,
   1376   1.1  christos   simple_object_mach_o_fetch_attributes,
   1377   1.1  christos   simple_object_mach_o_release_read,
   1378   1.1  christos   simple_object_mach_o_attributes_merge,
   1379   1.1  christos   simple_object_mach_o_release_attributes,
   1380   1.1  christos   simple_object_mach_o_start_write,
   1381   1.1  christos   simple_object_mach_o_write_to_file,
   1382   1.6  christos   simple_object_mach_o_release_write,
   1383   1.6  christos   NULL
   1384   1.1  christos };
   1385