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_merge (void *todata
, void *fromdata
, int *err
)
629 struct simple_object_mach_o_attributes
*to
=
630 (struct simple_object_mach_o_attributes
*) todata
;
631 struct simple_object_mach_o_attributes
*from
=
632 (struct simple_object_mach_o_attributes
*) fromdata
;
634 if (to
->magic
!= from
->magic
635 || to
->is_big_endian
!= from
->is_big_endian
636 || to
->cputype
!= from
->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_merge
,
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