1/* simple-object-mach-o.c -- routines to manipulate Mach-O object files.
2   Copyright 2010, 2011, 2013 Free Software Foundation, Inc.
3   Written by Ian Lance Taylor, Google.
4
5This program is free software; you can redistribute it and/or modify it
6under the terms of the GNU General Public License as published by the
7Free Software Foundation; either version 2, or (at your option) any
8later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, 51 Franklin Street - Fifth Floor,
18Boston, 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
48struct 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
61struct 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
85struct 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
98struct 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
115struct 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
132struct 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
149struct 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
188struct 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
210struct 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
239static void *
240simple_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
344static void
345simple_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
403static int
404simple_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
738static const char *
739simple_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
809static void *
810simple_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
830static void
831simple_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
842static const char *
843simple_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
862static void
863simple_object_mach_o_release_attributes (void *data)
864{
865  XDELETE (data);
866}
867
868/* Prepare to write out a file.  */
869
870static void *
871simple_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
888static int
889simple_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
939static int
940simple_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
1028static int
1029simple_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      sechdr_offset += sechdrsize;
1229
1230      /* Write out the section names.
1231	 ... the header ...
1232	 name_offset contains the length of the section.  It is not aligned.  */
1233
1234      if (!simple_object_mach_o_write_section_header (sobj, descriptor,
1235						      sechdr_offset,
1236						      GNU_WRAPPER_NAMES,
1237						      sobj->segment_name,
1238						      0 /*secaddr*/,
1239						      name_offset,
1240						      offset,
1241						      0, errmsg, err))
1242	return 0;
1243
1244      /* ... and the content.. */
1245      if (!simple_object_internal_write (descriptor, offset,
1246					 (const unsigned char *) snames,
1247					 name_offset, errmsg, err))
1248	return 0;
1249
1250      sechdr_offset += sechdrsize;
1251      secaddr += name_offset;
1252      offset += name_offset;
1253
1254      /* Now do the index, we'll align this to 4 bytes although the read code
1255	 will handle unaligned.  */
1256
1257      offset += 3;
1258      offset &= ~0x03;
1259      if (!simple_object_mach_o_write_section_header (sobj, descriptor,
1260						      sechdr_offset,
1261						      GNU_WRAPPER_INDEX,
1262						      sobj->segment_name,
1263						      0 /*secaddr*/,
1264						      nsects_in * 16,
1265						      offset,
1266						      2, errmsg, err))
1267	return 0;
1268
1269      /* ... and the content.. */
1270      if (!simple_object_internal_write (descriptor, offset,
1271					 (const unsigned char *) index,
1272					 nsects_in*16, errmsg, err))
1273	return 0;
1274
1275      XDELETEVEC (index);
1276      XDELETEVEC (snames);
1277    }
1278
1279  /* Write out the segment header.  */
1280
1281  memset (hdrbuf, 0, sizeof hdrbuf);
1282
1283  hdr = &hdrbuf[0];
1284  if (attrs->magic == MACH_O_MH_MAGIC)
1285    {
1286      set_32 (hdr + offsetof (struct mach_o_segment_command_32, cmd),
1287	      MACH_O_LC_SEGMENT);
1288      set_32 (hdr + offsetof (struct mach_o_segment_command_32, cmdsize),
1289	      cmdsize);
1290     /* MH_OBJECTS have a single, anonymous, segment - so the segment name
1291	 is left empty.  */
1292      /* vmaddr left as zero.  */
1293      /* vmsize left as zero.  */
1294      set_32 (hdr + offsetof (struct mach_o_segment_command_32, fileoff),
1295	      hdrsize + cmdsize);
1296      set_32 (hdr + offsetof (struct mach_o_segment_command_32, filesize),
1297	      offset - (hdrsize + cmdsize));
1298      /* maxprot left as zero.  */
1299      /* initprot left as zero.  */
1300      set_32 (hdr + offsetof (struct mach_o_segment_command_32, nsects),
1301	      *nsects);
1302      /* flags left as zero.  */
1303    }
1304  else
1305    {
1306#ifdef UNSIGNED_64BIT_TYPE
1307      void (*set_64) (unsigned char *, ulong_type);
1308
1309      set_64 = (attrs->is_big_endian
1310		? simple_object_set_big_64
1311		: simple_object_set_little_64);
1312
1313      set_32 (hdr + offsetof (struct mach_o_segment_command_64, cmd),
1314	      MACH_O_LC_SEGMENT);
1315      set_32 (hdr + offsetof (struct mach_o_segment_command_64, cmdsize),
1316	      cmdsize);
1317      /* MH_OBJECTS have a single, anonymous, segment - so the segment name
1318	 is left empty.  */
1319      /* vmaddr left as zero.  */
1320      /* vmsize left as zero.  */
1321      set_64 (hdr + offsetof (struct mach_o_segment_command_64, fileoff),
1322	      hdrsize + cmdsize);
1323      set_64 (hdr + offsetof (struct mach_o_segment_command_64, filesize),
1324	      offset - (hdrsize + cmdsize));
1325      /* maxprot left as zero.  */
1326      /* initprot left as zero.  */
1327      set_32 (hdr + offsetof (struct mach_o_segment_command_64, nsects),
1328	      *nsects);
1329      /* flags left as zero.  */
1330#endif
1331    }
1332
1333  return simple_object_internal_write (descriptor, hdrsize, hdr, seghdrsize,
1334				       errmsg, err);
1335}
1336
1337/* Write out a complete Mach-O file.  */
1338
1339static const char *
1340simple_object_mach_o_write_to_file (simple_object_write *sobj, int descriptor,
1341				    int *err)
1342{
1343  size_t nsects = 0;
1344  const char *errmsg;
1345
1346  if (!simple_object_mach_o_write_segment (sobj, descriptor, &nsects,
1347					   &errmsg, err))
1348    return errmsg;
1349
1350  if (!simple_object_mach_o_write_header (sobj, descriptor, nsects,
1351					  &errmsg, err))
1352    return errmsg;
1353
1354  return NULL;
1355}
1356
1357/* Release the private data for an simple_object_write structure.  */
1358
1359static void
1360simple_object_mach_o_release_write (void *data)
1361{
1362  XDELETE (data);
1363}
1364
1365/* The Mach-O functions.  */
1366
1367const struct simple_object_functions simple_object_mach_o_functions =
1368{
1369  simple_object_mach_o_match,
1370  simple_object_mach_o_find_sections,
1371  simple_object_mach_o_fetch_attributes,
1372  simple_object_mach_o_release_read,
1373  simple_object_mach_o_attributes_merge,
1374  simple_object_mach_o_release_attributes,
1375  simple_object_mach_o_start_write,
1376  simple_object_mach_o_write_to_file,
1377  simple_object_mach_o_release_write
1378};
1379