1 /* simple-object-mach-o.c -- routines to manipulate Mach-O object files.
2    Copyright (C) 2010-2024 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 *
simple_object_mach_o_match(unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN],int descriptor,off_t offset,const char * segment_name,const char ** errmsg,int * err)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
simple_object_mach_o_section_info(int is_big_endian,int is_32,const unsigned char * sechdr,off_t * offset,size_t * size)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
simple_object_mach_o_segment(simple_object_read * sobj,off_t offset,const unsigned char * segbuf,int (* pfn)(void *,const char *,off_t offset,off_t length),void * data,const char ** errmsg,int * err)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 *
simple_object_mach_o_find_sections(simple_object_read * sobj,int (* pfn)(void *,const char *,off_t offset,off_t length),void * data,int * err)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 *
simple_object_mach_o_fetch_attributes(simple_object_read * sobj,const char ** errmsg ATTRIBUTE_UNUSED,int * err ATTRIBUTE_UNUSED)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
simple_object_mach_o_release_read(void * data)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 *
simple_object_mach_o_attributes_merge(void * todata,void * fromdata,int * err)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
simple_object_mach_o_release_attributes(void * data)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 *
simple_object_mach_o_start_write(void * attributes_data,const char ** errmsg ATTRIBUTE_UNUSED,int * err ATTRIBUTE_UNUSED)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
simple_object_mach_o_write_header(simple_object_write * sobj,int descriptor,size_t nsects,const char ** errmsg,int * err)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
simple_object_mach_o_write_section_header(simple_object_write * sobj,int descriptor,size_t sechdr_offset,const char * name,const char * segn,size_t secaddr,size_t secsize,size_t offset,unsigned int align,const char ** errmsg,int * err)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
simple_object_mach_o_write_segment(simple_object_write * sobj,int descriptor,size_t * nsects,const char ** errmsg,int * err)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 *
simple_object_mach_o_write_to_file(simple_object_write * sobj,int descriptor,int * err)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
simple_object_mach_o_release_write(void * data)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 };
1385