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.
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
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.
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. */
21 #include "libiberty.h"
22 #include "simple-object.h"
38 #ifdef HAVE_INTTYPES_H
42 #include "simple-object-common.h"
44 /* Mach-O structures and constants. */
46 /* Mach-O header (32-bit version). */
48 struct mach_o_header_32
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. */
59 /* Mach-O header (64-bit version). */
61 struct mach_o_header_64
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. */
73 /* For magic field in header. */
75 #define MACH_O_MH_MAGIC 0xfeedface
76 #define MACH_O_MH_MAGIC_64 0xfeedfacf
78 /* For filetype field in header. */
80 #define MACH_O_MH_OBJECT 0x01
82 /* A Mach-O file is a list of load commands. This is the header of a
85 struct mach_o_load_command
87 unsigned char cmd[4]; /* The type of load command. */
88 unsigned char cmdsize[4]; /* Size in bytes of entire command. */
91 /* For cmd field in load command. */
93 #define MACH_O_LC_SEGMENT 0x01
94 #define MACH_O_LC_SEGMENT_64 0x19
96 /* LC_SEGMENT load command. */
98 struct mach_o_segment_command_32
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. */
113 /* LC_SEGMENT_64 load command. */
115 struct mach_o_segment_command_64
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. */
130 /* 32-bit section header. */
132 struct mach_o_section_32
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];
147 /* 64-bit section header. */
149 struct mach_o_section_64
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];
165 /* Flags for Mach-O sections. */
167 #define MACH_O_S_ATTR_DEBUG 0x02000000
169 /* The length of a segment or section name. */
171 #define MACH_O_NAME_LEN (16)
173 /* A GNU specific extension for long section names. */
175 #define GNU_SECTION_NAMES "__section_names"
177 /* Private data for an simple_object_read. */
179 struct simple_object_mach_o_read
181 /* User specified segment name. */
185 /* Whether this file 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. */
193 /* Flags from header. */
195 /* Reserved field from header, only used on 64-bit. */
196 unsigned int reserved;
199 /* Private data for an simple_object_attributes. */
201 struct simple_object_mach_o_attributes
205 /* Whether this file 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. */
213 /* Reserved field from header, only used on 64-bit. */
214 unsigned int reserved;
217 /* See if we have a Mach-O file. */
220 simple_object_mach_o_match (
221 unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN],
224 const char *segment_name,
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)];
236 magic = simple_object_fetch_big_32 (header);
237 if (magic == MACH_O_MH_MAGIC || magic == MACH_O_MH_MAGIC_64)
241 magic = simple_object_fetch_little_32 (header);
242 if (magic == MACH_O_MH_MAGIC || magic == MACH_O_MH_MAGIC_64)
252 #ifndef UNSIGNED_64BIT_TYPE
253 if (magic == MACH_O_MH_MAGIC_64)
255 *errmsg = "64-bit Mach-O objects not supported";
261 /* We require the user to provide a segment name. This is
262 unfortunate but I don't see any good choices here. */
264 if (segment_name == NULL)
266 *errmsg = "Mach-O file found but no segment name specified";
271 if (strlen (segment_name) > MACH_O_NAME_LEN)
273 *errmsg = "Mach-O segment name too long";
278 /* The 32-bit and 64-bit headers are similar enough that we can use
281 fetch_32 = (is_big_endian
282 ? simple_object_fetch_big_32
283 : simple_object_fetch_little_32);
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)),
294 filetype = (*fetch_32) (b + offsetof (struct mach_o_header_32, filetype));
295 if (filetype != MACH_O_MH_OBJECT)
297 *errmsg = "Mach-O file is not object file";
302 omr = XNEW (struct simple_object_mach_o_read);
303 omr->segment_name = xstrdup (segment_name);
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,
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)
315 omr->reserved = (*fetch_32) (b
316 + offsetof (struct mach_o_header_64,
322 /* Get the file offset and size from a section header. */
325 simple_object_mach_o_section_info (int is_big_endian, int is_32,
326 const unsigned char *sechdr, off_t *offset,
329 unsigned int (*fetch_32) (const unsigned char *);
330 ulong_type (*fetch_64) (const unsigned char *);
332 fetch_32 = (is_big_endian
333 ? simple_object_fetch_big_32
334 : simple_object_fetch_little_32);
337 #ifdef UNSIGNED_64BIT_TYPE
338 fetch_64 = (is_big_endian
339 ? simple_object_fetch_big_64
340 : simple_object_fetch_little_64);
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));
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));
359 /* Handle a segment in a Mach-O file. Return 1 if we should continue,
360 0 if the caller should return. */
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,
368 const char **errmsg, int *err)
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 *);
376 size_t segname_offset;
377 size_t sectname_offset;
379 unsigned char *secdata;
381 unsigned int strtab_index;
385 fetch_32 = (omr->is_big_endian
386 ? simple_object_fetch_big_32
387 : simple_object_fetch_little_32);
389 is_32 = omr->magic == MACH_O_MH_MAGIC;
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,
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,
412 secdata = XNEWVEC (unsigned char, nsects * sechdrsize);
413 if (!simple_object_internal_read (sobj->descriptor, offset + seghdrsize,
414 secdata, nsects * sechdrsize, errmsg, err))
416 XDELETEVEC (secdata);
420 /* Scan for a __section_names section. This is in effect a GNU
421 extension that permits section names longer than 16 chars. */
423 for (i = 0; i < nsects; ++i)
427 nameoff = i * sechdrsize + segname_offset;
428 if (strcmp ((char *) secdata + nameoff, omr->segment_name) != 0)
430 nameoff = i * sechdrsize + sectname_offset;
431 if (strcmp ((char *) secdata + nameoff, GNU_SECTION_NAMES) == 0)
436 if (strtab_index >= nsects)
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,
455 XDELETEVEC (secdata);
460 /* Process the sections. */
462 for (i = 0; i < nsects; ++i)
464 const unsigned char *sechdr;
465 char namebuf[MACH_O_NAME_LEN + 1];
470 if (i == strtab_index)
473 sechdr = secdata + i * sechdrsize;
475 if (strcmp ((char *) sechdr + segname_offset, omr->segment_name) != 0)
478 memcpy (namebuf, sechdr + sectname_offset, MACH_O_NAME_LEN);
479 namebuf[MACH_O_NAME_LEN] = '\0';
482 if (strtab != NULL && name[0] == '_' && name[1] == '_')
484 unsigned long stringoffset;
486 if (sscanf (name + 2, "%08lX", &stringoffset) == 1)
488 if (stringoffset >= strtab_size)
490 *errmsg = "section name offset out of range";
493 XDELETEVEC (secdata);
497 name = strtab + stringoffset;
501 simple_object_mach_o_section_info (omr->is_big_endian, is_32, sechdr,
502 &secoffset, &secsize);
504 if (!(*pfn) (data, name, secoffset, secsize))
509 XDELETEVEC (secdata);
515 XDELETEVEC (secdata);
520 /* Find all sections in a Mach-O file. */
523 simple_object_mach_o_find_sections (simple_object_read *sobj,
524 int (*pfn) (void *, const char *,
525 off_t offset, off_t length),
529 struct simple_object_mach_o_read *omr =
530 (struct simple_object_mach_o_read *) sobj->data;
533 unsigned int (*fetch_32) (const unsigned char *);
537 if (omr->magic == MACH_O_MH_MAGIC)
539 offset = sizeof (struct mach_o_header_32);
540 seghdrsize = sizeof (struct mach_o_segment_command_32);
544 offset = sizeof (struct mach_o_header_64);
545 seghdrsize = sizeof (struct mach_o_segment_command_64);
548 fetch_32 = (omr->is_big_endian
549 ? simple_object_fetch_big_32
550 : simple_object_fetch_little_32);
552 for (i = 0; i < omr->ncmds; ++i)
554 unsigned char loadbuf[sizeof (struct mach_o_load_command)];
556 unsigned int cmdsize;
558 if (!simple_object_internal_read (sobj->descriptor,
559 sobj->offset + offset,
561 sizeof (struct mach_o_load_command),
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));
569 if (cmd == MACH_O_LC_SEGMENT || cmd == MACH_O_LC_SEGMENT_64)
571 unsigned char segbuf[sizeof (struct mach_o_segment_command_64)];
574 if (!simple_object_internal_read (sobj->descriptor,
575 sobj->offset + offset,
576 segbuf, seghdrsize, &errmsg, err))
579 r = simple_object_mach_o_segment (sobj, offset, segbuf, pfn,
591 /* Fetch the attributes for an simple_object_read. */
594 simple_object_mach_o_fetch_attributes (simple_object_read *sobj,
595 const char **errmsg ATTRIBUTE_UNUSED,
596 int *err ATTRIBUTE_UNUSED)
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;
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;
612 /* Release the private data for an simple_object_read. */
615 simple_object_mach_o_release_read (void *data)
617 struct simple_object_mach_o_read *omr =
618 (struct simple_object_mach_o_read *) data;
620 free (omr->segment_name);
624 /* Compare two attributes structures. */
627 simple_object_mach_o_attributes_compare (void *data1, void *data2, int *err)
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;
634 if (attrs1->magic != attrs2->magic
635 || attrs1->is_big_endian != attrs2->is_big_endian
636 || attrs1->cputype != attrs2->cputype)
639 return "Mach-O object format mismatch";
644 /* Release the private data for an attributes structure. */
647 simple_object_mach_o_release_attributes (void *data)
652 /* Prepare to write out a file. */
655 simple_object_mach_o_start_write (void *attributes_data,
656 const char **errmsg ATTRIBUTE_UNUSED,
657 int *err ATTRIBUTE_UNUSED)
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;
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);
670 /* Write out the header of a Mach-O file. */
673 simple_object_mach_o_write_header (simple_object_write *sobj, int descriptor,
674 size_t nsects, const char **errmsg,
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)];
684 set_32 = (attrs->is_big_endian
685 ? simple_object_set_big_32
686 : simple_object_set_little_32);
688 memset (hdrbuf, 0, sizeof hdrbuf);
690 /* The 32-bit and 64-bit headers start out the same. */
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),
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)
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)));
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),
714 wrsize = sizeof (struct mach_o_header_64);
717 return simple_object_internal_write (descriptor, 0, hdrbuf, wrsize,
721 /* Write a Mach-O section header. */
724 simple_object_mach_o_write_section_header (simple_object_write *sobj,
726 size_t sechdr_offset,
727 const char *name, size_t secaddr,
728 size_t secsize, size_t offset,
730 const char **errmsg, int *err)
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)];
739 set_32 = (attrs->is_big_endian
740 ? simple_object_set_big_32
741 : simple_object_set_little_32);
743 memset (hdrbuf, 0, sizeof hdrbuf);
746 if (attrs->magic == MACH_O_MH_MAGIC)
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);
766 #ifdef UNSIGNED_64BIT_TYPE
767 void (*set_64) (unsigned char *, ulong_type);
769 set_64 = (attrs->is_big_endian
770 ? simple_object_set_big_64
771 : simple_object_set_little_64);
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. */
789 sechdrsize = sizeof (struct mach_o_section_64);
792 return simple_object_internal_write (descriptor, sechdr_offset, hdr,
793 sechdrsize, errmsg, err);
796 /* Write out the single segment and the sections of a Mach-O file. */
799 simple_object_mach_o_write_segment (simple_object_write *sobj, int descriptor,
800 size_t nsects, const char **errmsg,
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);
811 size_t sechdr_offset;
813 unsigned int name_offset;
814 simple_object_write_section *section;
815 unsigned char hdrbuf[sizeof (struct mach_o_segment_command_64)];
818 set_32 = (attrs->is_big_endian
819 ? simple_object_set_big_32
820 : simple_object_set_little_32);
822 /* Write out the sections first. */
824 if (attrs->magic == MACH_O_MH_MAGIC)
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);
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);
837 sechdr_offset = hdrsize + seghdrsize;
838 cmdsize = seghdrsize + nsects * sechdrsize;
839 offset = hdrsize + cmdsize;
843 for (section = sobj->sections; section != NULL; section = section->next)
848 struct simple_object_write_section_buffer *buffer;
849 char namebuf[MACH_O_NAME_LEN + 1];
851 mask = (1U << section->align) - 1;
852 new_offset = offset + mask;
853 new_offset &= ~ mask;
854 while (new_offset > offset)
856 unsigned char zeroes[16];
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,
870 for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
872 if (!simple_object_internal_write (descriptor, offset + secsize,
873 ((const unsigned char *)
875 buffer->size, errmsg, err))
877 secsize += buffer->size;
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,
888 sechdr_offset += sechdrsize;
890 name_offset += strlen (section->name) + 1;
894 /* Write out the section names. */
896 if (!simple_object_mach_o_write_section_header (sobj, descriptor,
898 GNU_SECTION_NAMES, secaddr,
899 name_offset, offset, 0,
903 for (section = sobj->sections; section != NULL; section = section->next)
907 namelen = strlen (section->name) + 1;
908 if (!simple_object_internal_write (descriptor, offset,
909 (const unsigned char *) section->name,
910 namelen, errmsg, err))
915 /* Write out the segment header. */
917 memset (hdrbuf, 0, sizeof hdrbuf);
920 if (attrs->magic == MACH_O_MH_MAGIC)
922 set_32 (hdr + offsetof (struct mach_o_segment_command_32, cmd),
924 set_32 (hdr + offsetof (struct mach_o_segment_command_32, 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),
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),
939 /* flags left as zero. */
943 #ifdef UNSIGNED_64BIT_TYPE
944 void (*set_64) (unsigned char *, ulong_type);
946 set_64 = (attrs->is_big_endian
947 ? simple_object_set_big_64
948 : simple_object_set_little_64);
950 set_32 (hdr + offsetof (struct mach_o_segment_command_64, cmd),
952 set_32 (hdr + offsetof (struct mach_o_segment_command_64, 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),
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),
967 /* flags left as zero. */
971 return simple_object_internal_write (descriptor, hdrsize, hdr, seghdrsize,
975 /* Write out a complete Mach-O file. */
978 simple_object_mach_o_write_to_file (simple_object_write *sobj, int descriptor,
982 simple_object_write_section *section;
985 /* Start at 1 for symbol_names section. */
987 for (section = sobj->sections; section != NULL; section = section->next)
990 if (!simple_object_mach_o_write_header (sobj, descriptor, nsects,
994 if (!simple_object_mach_o_write_segment (sobj, descriptor, nsects,
1001 /* Release the private data for an simple_object_write structure. */
1004 simple_object_mach_o_release_write (void *data)
1009 /* The Mach-O functions. */
1011 const struct simple_object_functions simple_object_mach_o_functions =
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