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