Merge branch 'vendor/DIFFUTILS'
[dragonfly.git] / contrib / binutils-2.21 / libiberty / simple-object-mach-o.c
1 /* simple-object-mach-o.c -- routines to manipulate Mach-O object files.
2    Copyright 2010 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 /* Private data for an simple_object_read.  */
178
179 struct simple_object_mach_o_read
180 {
181   /* User specified segment name.  */
182   char *segment_name;
183   /* Magic number.  */
184   unsigned int magic;
185   /* Whether this file is big-endian.  */
186   int is_big_endian;
187   /* CPU type from header.  */
188   unsigned int cputype;
189   /* CPU subtype from header.  */
190   unsigned int cpusubtype;
191   /* Number of commands, from header.  */
192   unsigned int ncmds;
193   /* Flags from header.  */
194   unsigned int flags;
195   /* Reserved field from header, only used on 64-bit.  */
196   unsigned int reserved;
197 };
198
199 /* Private data for an simple_object_attributes.  */
200
201 struct simple_object_mach_o_attributes
202 {
203   /* Magic number.  */
204   unsigned int magic;
205   /* Whether this file is big-endian.  */
206   int is_big_endian;
207   /* CPU type from header.  */
208   unsigned int cputype;
209   /* CPU subtype from header.  */
210   unsigned int cpusubtype;
211   /* Flags from header.  */
212   unsigned int flags;
213   /* Reserved field from header, only used on 64-bit.  */
214   unsigned int reserved;
215 };
216
217 /* See if we have a Mach-O file.  */
218
219 static void *
220 simple_object_mach_o_match (
221     unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN],
222     int descriptor,
223     off_t offset,
224     const char *segment_name,
225     const char **errmsg,
226     int *err)
227 {
228   unsigned int magic;
229   int is_big_endian;
230   unsigned int (*fetch_32) (const unsigned char *);
231   unsigned int filetype;
232   struct simple_object_mach_o_read *omr;
233   unsigned char buf[sizeof (struct mach_o_header_64)];
234   unsigned char *b;
235
236   magic = simple_object_fetch_big_32 (header);
237   if (magic == MACH_O_MH_MAGIC || magic == MACH_O_MH_MAGIC_64)
238     is_big_endian = 1;
239   else
240     {
241       magic = simple_object_fetch_little_32 (header);
242       if (magic == MACH_O_MH_MAGIC || magic == MACH_O_MH_MAGIC_64)
243         is_big_endian = 0;
244       else
245         {
246           *errmsg = NULL;
247           *err = 0;
248           return NULL;
249         }
250     }
251
252 #ifndef UNSIGNED_64BIT_TYPE
253   if (magic == MACH_O_MH_MAGIC_64)
254     {
255       *errmsg = "64-bit Mach-O objects not supported";
256       *err = 0;
257       return NULL;
258     }
259 #endif
260
261   /* We require the user to provide a segment name.  This is
262      unfortunate but I don't see any good choices here.  */
263
264   if (segment_name == NULL)
265     {
266       *errmsg = "Mach-O file found but no segment name specified";
267       *err = 0;
268       return NULL;
269     }
270
271   if (strlen (segment_name) > MACH_O_NAME_LEN)
272     {
273       *errmsg = "Mach-O segment name too long";
274       *err = 0;
275       return NULL;
276     }
277
278   /* The 32-bit and 64-bit headers are similar enough that we can use
279      the same code.  */
280
281   fetch_32 = (is_big_endian
282               ? simple_object_fetch_big_32
283               : simple_object_fetch_little_32);
284
285   if (!simple_object_internal_read (descriptor, offset, buf,
286                                     (magic == MACH_O_MH_MAGIC
287                                      ? sizeof (struct mach_o_header_32)
288                                      : sizeof (struct mach_o_header_64)),
289                                     errmsg, err))
290     return NULL;
291
292   b = &buf[0];
293
294   filetype = (*fetch_32) (b + offsetof (struct mach_o_header_32, filetype));
295   if (filetype != MACH_O_MH_OBJECT)
296     {
297       *errmsg = "Mach-O file is not object file";
298       *err = 0;
299       return NULL;
300     }
301
302   omr = XNEW (struct simple_object_mach_o_read);
303   omr->segment_name = xstrdup (segment_name);
304   omr->magic = magic;
305   omr->is_big_endian = is_big_endian;
306   omr->cputype = (*fetch_32) (b + offsetof (struct mach_o_header_32, cputype));
307   omr->cpusubtype = (*fetch_32) (b
308                                  + offsetof (struct mach_o_header_32,
309                                              cpusubtype));
310   omr->ncmds = (*fetch_32) (b + offsetof (struct mach_o_header_32, ncmds));
311   omr->flags = (*fetch_32) (b + offsetof (struct mach_o_header_32, flags));
312   if (magic == MACH_O_MH_MAGIC)
313     omr->reserved = 0;
314   else
315     omr->reserved = (*fetch_32) (b
316                                  + offsetof (struct mach_o_header_64,
317                                              reserved));
318
319   return (void *) omr;
320 }
321
322 /* Get the file offset and size from a section header.  */
323
324 static void
325 simple_object_mach_o_section_info (int is_big_endian, int is_32,
326                                    const unsigned char *sechdr, off_t *offset,
327                                    size_t *size)
328 {
329   unsigned int (*fetch_32) (const unsigned char *);
330   ulong_type (*fetch_64) (const unsigned char *);
331
332   fetch_32 = (is_big_endian
333               ? simple_object_fetch_big_32
334               : simple_object_fetch_little_32);
335
336   fetch_64 = NULL;
337 #ifdef UNSIGNED_64BIT_TYPE
338   fetch_64 = (is_big_endian
339               ? simple_object_fetch_big_64
340               : simple_object_fetch_little_64);
341 #endif
342
343   if (is_32)
344     {
345       *offset = fetch_32 (sechdr
346                           + offsetof (struct mach_o_section_32, offset));
347       *size = fetch_32 (sechdr
348                         + offsetof (struct mach_o_section_32, size));
349     }
350   else
351     {
352       *offset = fetch_32 (sechdr
353                           + offsetof (struct mach_o_section_64, offset));
354       *size = fetch_64 (sechdr
355                         + offsetof (struct mach_o_section_64, size));
356     }
357 }
358
359 /* Handle a segment in a Mach-O file.  Return 1 if we should continue,
360    0 if the caller should return.  */
361
362 static int
363 simple_object_mach_o_segment (simple_object_read *sobj, off_t offset,
364                               const unsigned char *segbuf,
365                               int (*pfn) (void *, const char *, off_t offset,
366                                           off_t length),
367                               void *data,
368                               const char **errmsg, int *err)
369 {
370   struct simple_object_mach_o_read *omr =
371     (struct simple_object_mach_o_read *) sobj->data;
372   unsigned int (*fetch_32) (const unsigned char *);
373   int is_32;
374   size_t seghdrsize;
375   size_t sechdrsize;
376   size_t segname_offset;
377   size_t sectname_offset;
378   unsigned int nsects;
379   unsigned char *secdata;
380   unsigned int i;
381   unsigned int strtab_index;
382   char *strtab;
383   size_t strtab_size;
384
385   fetch_32 = (omr->is_big_endian
386               ? simple_object_fetch_big_32
387               : simple_object_fetch_little_32);
388
389   is_32 = omr->magic == MACH_O_MH_MAGIC;
390
391   if (is_32)
392     {
393       seghdrsize = sizeof (struct mach_o_segment_command_32);
394       sechdrsize = sizeof (struct mach_o_section_32);
395       segname_offset = offsetof (struct mach_o_section_32, segname);
396       sectname_offset = offsetof (struct mach_o_section_32, sectname);
397       nsects = (*fetch_32) (segbuf
398                             + offsetof (struct mach_o_segment_command_32,
399                                         nsects));
400     }
401   else
402     {
403       seghdrsize = sizeof (struct mach_o_segment_command_64);
404       sechdrsize = sizeof (struct mach_o_section_64);
405       segname_offset = offsetof (struct mach_o_section_64, segname);
406       sectname_offset = offsetof (struct mach_o_section_64, sectname);
407       nsects = (*fetch_32) (segbuf
408                             + offsetof (struct mach_o_segment_command_64,
409                                         nsects));
410     }
411
412   secdata = XNEWVEC (unsigned char, nsects * sechdrsize);
413   if (!simple_object_internal_read (sobj->descriptor, offset + seghdrsize,
414                                     secdata, nsects * sechdrsize, errmsg, err))
415     {
416       XDELETEVEC (secdata);
417       return 0;
418     }
419
420   /* Scan for a __section_names section.  This is in effect a GNU
421      extension that permits section names longer than 16 chars.  */
422
423   for (i = 0; i < nsects; ++i)
424     {
425       size_t nameoff;
426
427       nameoff = i * sechdrsize + segname_offset;
428       if (strcmp ((char *) secdata + nameoff, omr->segment_name) != 0)
429         continue;
430       nameoff = i * sechdrsize + sectname_offset;
431       if (strcmp ((char *) secdata + nameoff, GNU_SECTION_NAMES) == 0)
432         break;
433     }
434
435   strtab_index = i;
436   if (strtab_index >= nsects)
437     {
438       strtab = NULL;
439       strtab_size = 0;
440     }
441   else
442     {
443       off_t strtab_offset;
444
445       simple_object_mach_o_section_info (omr->is_big_endian, is_32,
446                                          secdata + strtab_index * sechdrsize,
447                                          &strtab_offset, &strtab_size);
448       strtab = XNEWVEC (char, strtab_size);
449       if (!simple_object_internal_read (sobj->descriptor,
450                                         sobj->offset + strtab_offset,
451                                         (unsigned char *) strtab, strtab_size,
452                                         errmsg, err))
453         {
454           XDELETEVEC (strtab);
455           XDELETEVEC (secdata);
456           return 0;
457         }
458     }
459
460   /* Process the sections.  */
461
462   for (i = 0; i < nsects; ++i)
463     {
464       const unsigned char *sechdr;
465       char namebuf[MACH_O_NAME_LEN + 1];
466       char *name;
467       off_t secoffset;
468       size_t secsize;
469
470       if (i == strtab_index)
471         continue;
472
473       sechdr = secdata + i * sechdrsize;
474
475       if (strcmp ((char *) sechdr + segname_offset, omr->segment_name) != 0)
476         continue;
477
478       memcpy (namebuf, sechdr + sectname_offset, MACH_O_NAME_LEN);
479       namebuf[MACH_O_NAME_LEN] = '\0';
480
481       name = &namebuf[0];
482       if (strtab != NULL && name[0] == '_' && name[1] == '_')
483         {
484           unsigned long stringoffset;
485
486           if (sscanf (name + 2, "%08lX", &stringoffset) == 1)
487             {
488               if (stringoffset >= strtab_size)
489                 {
490                   *errmsg = "section name offset out of range";
491                   *err = 0;
492                   XDELETEVEC (strtab);
493                   XDELETEVEC (secdata);
494                   return 0;
495                 }
496
497               name = strtab + stringoffset;
498             }
499         }
500
501       simple_object_mach_o_section_info (omr->is_big_endian, is_32, sechdr,
502                                          &secoffset, &secsize);
503
504       if (!(*pfn) (data, name, secoffset, secsize))
505         {
506           *errmsg = NULL;
507           *err = 0;
508           XDELETEVEC (strtab);
509           XDELETEVEC (secdata);
510           return 0;
511         }
512     }
513
514   XDELETEVEC (strtab);
515   XDELETEVEC (secdata);
516
517   return 1;
518 }
519
520 /* Find all sections in a Mach-O file.  */
521
522 static const char *
523 simple_object_mach_o_find_sections (simple_object_read *sobj,
524                                     int (*pfn) (void *, const char *,
525                                                 off_t offset, off_t length),
526                                     void *data,
527                                     int *err)
528 {
529   struct simple_object_mach_o_read *omr =
530     (struct simple_object_mach_o_read *) sobj->data;
531   off_t offset;
532   size_t seghdrsize;
533   unsigned int (*fetch_32) (const unsigned char *);
534   const char *errmsg;
535   unsigned int i;
536
537   if (omr->magic == MACH_O_MH_MAGIC)
538     {
539       offset = sizeof (struct mach_o_header_32);
540       seghdrsize = sizeof (struct mach_o_segment_command_32);
541     }
542   else
543     {
544       offset = sizeof (struct mach_o_header_64);
545       seghdrsize = sizeof (struct mach_o_segment_command_64);
546     }
547
548   fetch_32 = (omr->is_big_endian
549               ? simple_object_fetch_big_32
550               : simple_object_fetch_little_32);
551
552   for (i = 0; i < omr->ncmds; ++i)
553     {
554       unsigned char loadbuf[sizeof (struct mach_o_load_command)];
555       unsigned int cmd;
556       unsigned int cmdsize;
557
558       if (!simple_object_internal_read (sobj->descriptor,
559                                         sobj->offset + offset,
560                                         loadbuf,
561                                         sizeof (struct mach_o_load_command),
562                                         &errmsg, err))
563         return errmsg;
564
565       cmd = (*fetch_32) (loadbuf + offsetof (struct mach_o_load_command, cmd));
566       cmdsize = (*fetch_32) (loadbuf
567                              + offsetof (struct mach_o_load_command, cmdsize));
568
569       if (cmd == MACH_O_LC_SEGMENT || cmd == MACH_O_LC_SEGMENT_64)
570         {
571           unsigned char segbuf[sizeof (struct mach_o_segment_command_64)];
572           int r;
573
574           if (!simple_object_internal_read (sobj->descriptor,
575                                             sobj->offset + offset,
576                                             segbuf, seghdrsize, &errmsg, err))
577             return errmsg;
578
579           r = simple_object_mach_o_segment (sobj, offset, segbuf, pfn,
580                                             data, &errmsg, err);
581           if (!r)
582             return errmsg;
583         }
584
585       offset += cmdsize;
586     }
587
588   return NULL;
589 }
590
591 /* Fetch the attributes for an simple_object_read.  */
592
593 static void *
594 simple_object_mach_o_fetch_attributes (simple_object_read *sobj,
595                                        const char **errmsg ATTRIBUTE_UNUSED,
596                                        int *err ATTRIBUTE_UNUSED)
597 {
598   struct simple_object_mach_o_read *omr =
599     (struct simple_object_mach_o_read *) sobj->data;
600   struct simple_object_mach_o_attributes *ret;
601
602   ret = XNEW (struct simple_object_mach_o_attributes);
603   ret->magic = omr->magic;
604   ret->is_big_endian = omr->is_big_endian;
605   ret->cputype = omr->cputype;
606   ret->cpusubtype = omr->cpusubtype;
607   ret->flags = omr->flags;
608   ret->reserved = omr->reserved;
609   return ret;
610 }
611
612 /* Release the private data for an simple_object_read.  */
613
614 static void
615 simple_object_mach_o_release_read (void *data)
616 {
617   struct simple_object_mach_o_read *omr =
618     (struct simple_object_mach_o_read *) data;
619
620   free (omr->segment_name);
621   XDELETE (omr);
622 }
623
624 /* Compare two attributes structures.  */
625
626 static const char *
627 simple_object_mach_o_attributes_compare (void *data1, void *data2, int *err)
628 {
629   struct simple_object_mach_o_attributes *attrs1 =
630     (struct simple_object_mach_o_attributes *) data1;
631   struct simple_object_mach_o_attributes *attrs2 =
632     (struct simple_object_mach_o_attributes *) data2;
633
634   if (attrs1->magic != attrs2->magic
635       || attrs1->is_big_endian != attrs2->is_big_endian
636       || attrs1->cputype != attrs2->cputype)
637     {
638       *err = 0;
639       return "Mach-O object format mismatch";
640     }
641   return NULL;
642 }
643
644 /* Release the private data for an attributes structure.  */
645
646 static void
647 simple_object_mach_o_release_attributes (void *data)
648 {
649   XDELETE (data);
650 }
651
652 /* Prepare to write out a file.  */
653
654 static void *
655 simple_object_mach_o_start_write (void *attributes_data,
656                                   const char **errmsg ATTRIBUTE_UNUSED,
657                                   int *err ATTRIBUTE_UNUSED)
658 {
659   struct simple_object_mach_o_attributes *attrs =
660     (struct simple_object_mach_o_attributes *) attributes_data;
661   struct simple_object_mach_o_attributes *ret;
662
663   /* We're just going to record the attributes, but we need to make a
664      copy because the user may delete them.  */
665   ret = XNEW (struct simple_object_mach_o_attributes);
666   *ret = *attrs;
667   return ret;
668 }
669
670 /* Write out the header of a Mach-O file.  */
671
672 static int
673 simple_object_mach_o_write_header (simple_object_write *sobj, int descriptor,
674                                    size_t nsects, const char **errmsg,
675                                    int *err)
676 {
677   struct simple_object_mach_o_attributes *attrs =
678     (struct simple_object_mach_o_attributes *) sobj->data;
679   void (*set_32) (unsigned char *, unsigned int);
680   unsigned char hdrbuf[sizeof (struct mach_o_header_64)];
681   unsigned char *hdr;
682   size_t wrsize;
683
684   set_32 = (attrs->is_big_endian
685             ? simple_object_set_big_32
686             : simple_object_set_little_32);
687
688   memset (hdrbuf, 0, sizeof hdrbuf);
689
690   /* The 32-bit and 64-bit headers start out the same.  */
691
692   hdr = &hdrbuf[0];
693   set_32 (hdr + offsetof (struct mach_o_header_32, magic), attrs->magic);
694   set_32 (hdr + offsetof (struct mach_o_header_32, cputype), attrs->cputype);
695   set_32 (hdr + offsetof (struct mach_o_header_32, cpusubtype),
696           attrs->cpusubtype);
697   set_32 (hdr + offsetof (struct mach_o_header_32, filetype), MACH_O_MH_OBJECT);
698   set_32 (hdr + offsetof (struct mach_o_header_32, ncmds), 1);
699   set_32 (hdr + offsetof (struct mach_o_header_32, flags), attrs->flags);
700   if (attrs->magic == MACH_O_MH_MAGIC)
701     {
702       wrsize = sizeof (struct mach_o_header_32);
703       set_32 (hdr + offsetof (struct mach_o_header_32, sizeofcmds),
704               (sizeof (struct mach_o_segment_command_32)
705                + nsects * sizeof (struct mach_o_section_32)));
706     }
707   else
708     {
709       set_32 (hdr + offsetof (struct mach_o_header_64, sizeofcmds),
710               (sizeof (struct mach_o_segment_command_64)
711                + nsects * sizeof (struct mach_o_section_64)));
712       set_32 (hdr + offsetof (struct mach_o_header_64, reserved),
713               attrs->reserved);
714       wrsize = sizeof (struct mach_o_header_64);
715     }
716
717   return simple_object_internal_write (descriptor, 0, hdrbuf, wrsize,
718                                        errmsg, err);
719 }
720
721 /* Write a Mach-O section header.  */
722
723 static int
724 simple_object_mach_o_write_section_header (simple_object_write *sobj,
725                                            int descriptor,
726                                            size_t sechdr_offset,
727                                            const char *name, size_t secaddr,
728                                            size_t secsize, size_t offset,
729                                            unsigned int align,
730                                            const char **errmsg, int *err)
731 {
732   struct simple_object_mach_o_attributes *attrs =
733     (struct simple_object_mach_o_attributes *) sobj->data;
734   void (*set_32) (unsigned char *, unsigned int);
735   unsigned char hdrbuf[sizeof (struct mach_o_section_64)];
736   unsigned char *hdr;
737   size_t sechdrsize;
738
739   set_32 = (attrs->is_big_endian
740             ? simple_object_set_big_32
741             : simple_object_set_little_32);
742
743   memset (hdrbuf, 0, sizeof hdrbuf);
744
745   hdr = &hdrbuf[0];
746   if (attrs->magic == MACH_O_MH_MAGIC)
747     {
748       strncpy ((char *) hdr + offsetof (struct mach_o_section_32, sectname),
749                name, MACH_O_NAME_LEN);
750       strncpy ((char *) hdr + offsetof (struct mach_o_section_32, segname),
751                sobj->segment_name, MACH_O_NAME_LEN);
752       set_32 (hdr + offsetof (struct mach_o_section_32, addr), secaddr);
753       set_32 (hdr + offsetof (struct mach_o_section_32, size), secsize);
754       set_32 (hdr + offsetof (struct mach_o_section_32, offset), offset);
755       set_32 (hdr + offsetof (struct mach_o_section_32, align), align);
756       /* reloff left as zero.  */
757       /* nreloc left as zero.  */
758       set_32 (hdr + offsetof (struct mach_o_section_32, flags),
759               MACH_O_S_ATTR_DEBUG);
760       /* reserved1 left as zero.  */
761       /* reserved2 left as zero.  */
762       sechdrsize = sizeof (struct mach_o_section_32);
763     }
764   else
765     {
766 #ifdef UNSIGNED_64BIT_TYPE
767       void (*set_64) (unsigned char *, ulong_type);
768
769       set_64 = (attrs->is_big_endian
770                 ? simple_object_set_big_64
771                 : simple_object_set_little_64);
772
773       strncpy ((char *) hdr + offsetof (struct mach_o_section_64, sectname),
774                name, MACH_O_NAME_LEN);
775       strncpy ((char *) hdr + offsetof (struct mach_o_section_64, segname),
776                sobj->segment_name, MACH_O_NAME_LEN);
777       set_64 (hdr + offsetof (struct mach_o_section_64, addr), secaddr);
778       set_64 (hdr + offsetof (struct mach_o_section_64, size), secsize);
779       set_32 (hdr + offsetof (struct mach_o_section_64, offset), offset);
780       set_32 (hdr + offsetof (struct mach_o_section_64, align), align);
781       /* reloff left as zero.  */
782       /* nreloc left as zero.  */
783       set_32 (hdr + offsetof (struct mach_o_section_64, flags),
784               MACH_O_S_ATTR_DEBUG);
785       /* reserved1 left as zero.  */
786       /* reserved2 left as zero.  */
787       /* reserved3 left as zero.  */
788 #endif
789       sechdrsize = sizeof (struct mach_o_section_64);
790     }
791
792   return simple_object_internal_write (descriptor, sechdr_offset, hdr,
793                                        sechdrsize, errmsg, err);
794 }
795
796 /* Write out the single segment and the sections of a Mach-O file.  */
797
798 static int
799 simple_object_mach_o_write_segment (simple_object_write *sobj, int descriptor,
800                                     size_t nsects, const char **errmsg,
801                                     int *err)
802 {
803   struct simple_object_mach_o_attributes *attrs =
804     (struct simple_object_mach_o_attributes *) sobj->data;
805   void (*set_32) (unsigned char *, unsigned int);
806   size_t hdrsize;
807   size_t seghdrsize;
808   size_t sechdrsize;
809   size_t cmdsize;
810   size_t offset;
811   size_t sechdr_offset;
812   size_t secaddr;
813   unsigned int name_offset;
814   simple_object_write_section *section;
815   unsigned char hdrbuf[sizeof (struct mach_o_segment_command_64)];
816   unsigned char *hdr;
817
818   set_32 = (attrs->is_big_endian
819             ? simple_object_set_big_32
820             : simple_object_set_little_32);
821
822   /* Write out the sections first.  */
823
824   if (attrs->magic == MACH_O_MH_MAGIC)
825     {
826       hdrsize = sizeof (struct mach_o_header_32);
827       seghdrsize = sizeof (struct mach_o_segment_command_32);
828       sechdrsize = sizeof (struct mach_o_section_32);
829     }
830   else
831     {
832       hdrsize = sizeof (struct mach_o_header_64);
833       seghdrsize = sizeof (struct mach_o_segment_command_64);
834       sechdrsize = sizeof (struct mach_o_section_64);
835     }
836
837   sechdr_offset = hdrsize + seghdrsize;
838   cmdsize = seghdrsize + nsects * sechdrsize;
839   offset = hdrsize + cmdsize;
840   name_offset = 0;
841   secaddr = 0;
842
843   for (section = sobj->sections; section != NULL; section = section->next)
844     {
845       size_t mask;
846       size_t new_offset;
847       size_t secsize;
848       struct simple_object_write_section_buffer *buffer;
849       char namebuf[MACH_O_NAME_LEN + 1];
850
851       mask = (1U << section->align) - 1;
852       new_offset = offset + mask;
853       new_offset &= ~ mask;
854       while (new_offset > offset)
855         {
856           unsigned char zeroes[16];
857           size_t write;
858
859           memset (zeroes, 0, sizeof zeroes);
860           write = new_offset - offset;
861           if (write > sizeof zeroes)
862             write = sizeof zeroes;
863           if (!simple_object_internal_write (descriptor, offset, zeroes, write,
864                                              errmsg, err))
865             return 0;
866           offset += write;
867         }
868
869       secsize = 0;
870       for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
871         {
872           if (!simple_object_internal_write (descriptor, offset + secsize,
873                                              ((const unsigned char *)
874                                               buffer->buffer),
875                                              buffer->size, errmsg, err))
876             return 0;
877           secsize += buffer->size;
878         }
879
880       snprintf (namebuf, sizeof namebuf, "__%08X", name_offset);
881       if (!simple_object_mach_o_write_section_header (sobj, descriptor,
882                                                       sechdr_offset, namebuf,
883                                                       secaddr, secsize, offset,
884                                                       section->align,
885                                                       errmsg, err))
886         return 0;
887
888       sechdr_offset += sechdrsize;
889       offset += secsize;
890       name_offset += strlen (section->name) + 1;
891       secaddr += secsize;
892     }
893
894   /* Write out the section names.  */
895
896   if (!simple_object_mach_o_write_section_header (sobj, descriptor,
897                                                   sechdr_offset,
898                                                   GNU_SECTION_NAMES, secaddr,
899                                                   name_offset, offset, 0,
900                                                   errmsg, err))
901     return 0;
902
903   for (section = sobj->sections; section != NULL; section = section->next)
904     {
905       size_t namelen;
906
907       namelen = strlen (section->name) + 1;
908       if (!simple_object_internal_write (descriptor, offset,
909                                          (const unsigned char *) section->name,
910                                          namelen, errmsg, err))
911         return 0;
912       offset += namelen;
913     }
914
915   /* Write out the segment header.  */
916
917   memset (hdrbuf, 0, sizeof hdrbuf);
918
919   hdr = &hdrbuf[0];
920   if (attrs->magic == MACH_O_MH_MAGIC)
921     {
922       set_32 (hdr + offsetof (struct mach_o_segment_command_32, cmd),
923               MACH_O_LC_SEGMENT);
924       set_32 (hdr + offsetof (struct mach_o_segment_command_32, cmdsize),
925               cmdsize);
926       strncpy (((char *) hdr
927                 + offsetof (struct mach_o_segment_command_32, segname)),
928                sobj->segment_name, MACH_O_NAME_LEN);
929       /* vmaddr left as zero.  */
930       /* vmsize left as zero.  */
931       set_32 (hdr + offsetof (struct mach_o_segment_command_32, fileoff),
932               hdrsize + cmdsize);
933       set_32 (hdr + offsetof (struct mach_o_segment_command_32, filesize),
934               offset - (hdrsize + cmdsize));
935       /* maxprot left as zero.  */
936       /* initprot left as zero.  */
937       set_32 (hdr + offsetof (struct mach_o_segment_command_32, nsects),
938               nsects);
939       /* flags left as zero.  */
940     }
941   else
942     {
943 #ifdef UNSIGNED_64BIT_TYPE
944       void (*set_64) (unsigned char *, ulong_type);
945
946       set_64 = (attrs->is_big_endian
947                 ? simple_object_set_big_64
948                 : simple_object_set_little_64);
949
950       set_32 (hdr + offsetof (struct mach_o_segment_command_64, cmd),
951               MACH_O_LC_SEGMENT);
952       set_32 (hdr + offsetof (struct mach_o_segment_command_64, cmdsize),
953               cmdsize);
954       strncpy (((char *) hdr
955                 + offsetof (struct mach_o_segment_command_64, segname)),
956                sobj->segment_name, MACH_O_NAME_LEN);
957       /* vmaddr left as zero.  */
958       /* vmsize left as zero.  */
959       set_64 (hdr + offsetof (struct mach_o_segment_command_64, fileoff),
960               hdrsize + cmdsize);
961       set_64 (hdr + offsetof (struct mach_o_segment_command_64, filesize),
962               offset - (hdrsize + cmdsize));
963       /* maxprot left as zero.  */
964       /* initprot left as zero.  */
965       set_32 (hdr + offsetof (struct mach_o_segment_command_64, nsects),
966               nsects);
967       /* flags left as zero.  */
968 #endif
969     }
970
971   return simple_object_internal_write (descriptor, hdrsize, hdr, seghdrsize,
972                                        errmsg, err);
973 }
974
975 /* Write out a complete Mach-O file.  */
976
977 static const char *
978 simple_object_mach_o_write_to_file (simple_object_write *sobj, int descriptor,
979                                     int *err)
980 {
981   size_t nsects;
982   simple_object_write_section *section;
983   const char *errmsg;
984
985   /* Start at 1 for symbol_names section.  */
986   nsects = 1;
987   for (section = sobj->sections; section != NULL; section = section->next)
988     ++nsects;
989
990   if (!simple_object_mach_o_write_header (sobj, descriptor, nsects,
991                                           &errmsg, err))
992     return errmsg;
993
994   if (!simple_object_mach_o_write_segment (sobj, descriptor, nsects,
995                                            &errmsg, err))
996     return errmsg;
997
998   return NULL;
999 }
1000
1001 /* Release the private data for an simple_object_write structure.  */
1002
1003 static void
1004 simple_object_mach_o_release_write (void *data)
1005 {
1006   XDELETE (data);
1007 }
1008
1009 /* The Mach-O functions.  */
1010
1011 const struct simple_object_functions simple_object_mach_o_functions =
1012 {
1013   simple_object_mach_o_match,
1014   simple_object_mach_o_find_sections,
1015   simple_object_mach_o_fetch_attributes,
1016   simple_object_mach_o_release_read,
1017   simple_object_mach_o_attributes_compare,
1018   simple_object_mach_o_release_attributes,
1019   simple_object_mach_o_start_write,
1020   simple_object_mach_o_write_to_file,
1021   simple_object_mach_o_release_write
1022 };