2011-04-03 Tobias Burnus <burnus@net-b.de>
[official-gcc.git] / libiberty / simple-object-mach-o.c
blobbbbbd09de5809257344157e40cb64cfd7c8f3dba
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
8 later version.
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. */
20 #include "config.h"
21 #include "libiberty.h"
22 #include "simple-object.h"
24 #include <stddef.h>
26 #ifdef HAVE_STDLIB_H
27 #include <stdlib.h>
28 #endif
30 #ifdef HAVE_STDINT_H
31 #include <stdint.h>
32 #endif
34 #ifdef HAVE_STRING_H
35 #include <string.h>
36 #endif
38 #ifdef HAVE_INTTYPES_H
39 #include <inttypes.h>
40 #endif
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
83 load command. */
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. */
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;
199 /* Private data for an simple_object_attributes. */
201 struct simple_object_mach_o_attributes
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;
217 /* See if we have a Mach-O file. */
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)
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;
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
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
246 *errmsg = NULL;
247 *err = 0;
248 return NULL;
252 #ifndef UNSIGNED_64BIT_TYPE
253 if (magic == MACH_O_MH_MAGIC_64)
255 *errmsg = "64-bit Mach-O objects not supported";
256 *err = 0;
257 return NULL;
259 #endif
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";
267 *err = 0;
268 return NULL;
271 if (strlen (segment_name) > MACH_O_NAME_LEN)
273 *errmsg = "Mach-O segment name too long";
274 *err = 0;
275 return NULL;
278 /* The 32-bit and 64-bit headers are similar enough that we can use
279 the same code. */
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)),
289 errmsg, err))
290 return NULL;
292 b = &buf[0];
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";
298 *err = 0;
299 return NULL;
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));
319 return (void *) omr;
322 /* Get the file offset and size from a section header. */
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)
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);
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
343 if (is_32)
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));
350 else
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. */
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)
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;
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;
391 if (is_32)
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));
401 else
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));
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);
417 return 0;
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)
425 size_t nameoff;
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;
435 strtab_index = i;
436 if (strtab_index >= nsects)
438 strtab = NULL;
439 strtab_size = 0;
441 else
443 off_t strtab_offset;
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))
454 XDELETEVEC (strtab);
455 XDELETEVEC (secdata);
456 return 0;
460 /* Process the sections. */
462 for (i = 0; i < nsects; ++i)
464 const unsigned char *sechdr;
465 char namebuf[MACH_O_NAME_LEN + 1];
466 char *name;
467 off_t secoffset;
468 size_t secsize;
470 if (i == strtab_index)
471 continue;
473 sechdr = secdata + i * sechdrsize;
475 if (strcmp ((char *) sechdr + segname_offset, omr->segment_name) != 0)
476 continue;
478 memcpy (namebuf, sechdr + sectname_offset, MACH_O_NAME_LEN);
479 namebuf[MACH_O_NAME_LEN] = '\0';
481 name = &namebuf[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";
491 *err = 0;
492 XDELETEVEC (strtab);
493 XDELETEVEC (secdata);
494 return 0;
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))
506 *errmsg = NULL;
507 *err = 0;
508 XDELETEVEC (strtab);
509 XDELETEVEC (secdata);
510 return 0;
514 XDELETEVEC (strtab);
515 XDELETEVEC (secdata);
517 return 1;
520 /* Find all sections in a Mach-O file. */
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)
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;
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);
542 else
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)];
555 unsigned int cmd;
556 unsigned int cmdsize;
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;
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)];
572 int r;
574 if (!simple_object_internal_read (sobj->descriptor,
575 sobj->offset + offset,
576 segbuf, seghdrsize, &errmsg, err))
577 return errmsg;
579 r = simple_object_mach_o_segment (sobj, offset, segbuf, pfn,
580 data, &errmsg, err);
581 if (!r)
582 return errmsg;
585 offset += cmdsize;
588 return NULL;
591 /* Fetch the attributes for an simple_object_read. */
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)
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;
609 return ret;
612 /* Release the private data for an simple_object_read. */
614 static void
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);
621 XDELETE (omr);
624 /* Compare two attributes structures. */
626 static const char *
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)
638 *err = 0;
639 return "Mach-O object format mismatch";
641 return NULL;
644 /* Release the private data for an attributes structure. */
646 static void
647 simple_object_mach_o_release_attributes (void *data)
649 XDELETE (data);
652 /* Prepare to write out a file. */
654 static void *
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);
666 *ret = *attrs;
667 return ret;
670 /* Write out the header of a Mach-O file. */
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)
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;
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. */
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)
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)));
707 else
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);
717 return simple_object_internal_write (descriptor, 0, hdrbuf, wrsize,
718 errmsg, err);
721 /* Write a Mach-O section header. */
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)
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;
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);
745 hdr = &hdrbuf[0];
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);
764 else
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. */
788 #endif
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. */
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)
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;
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);
830 else
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;
840 name_offset = 0;
841 secaddr = 0;
843 for (section = sobj->sections; section != NULL; section = section->next)
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];
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];
857 size_t write;
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;
869 secsize = 0;
870 for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
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;
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;
888 sechdr_offset += sechdrsize;
889 offset += secsize;
890 name_offset += strlen (section->name) + 1;
891 secaddr += secsize;
894 /* Write out the section names. */
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;
903 for (section = sobj->sections; section != NULL; section = section->next)
905 size_t namelen;
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;
915 /* Write out the segment header. */
917 memset (hdrbuf, 0, sizeof hdrbuf);
919 hdr = &hdrbuf[0];
920 if (attrs->magic == MACH_O_MH_MAGIC)
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. */
941 else
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),
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
971 return simple_object_internal_write (descriptor, hdrsize, hdr, seghdrsize,
972 errmsg, err);
975 /* Write out a complete Mach-O file. */
977 static const char *
978 simple_object_mach_o_write_to_file (simple_object_write *sobj, int descriptor,
979 int *err)
981 size_t nsects;
982 simple_object_write_section *section;
983 const char *errmsg;
985 /* Start at 1 for symbol_names section. */
986 nsects = 1;
987 for (section = sobj->sections; section != NULL; section = section->next)
988 ++nsects;
990 if (!simple_object_mach_o_write_header (sobj, descriptor, nsects,
991 &errmsg, err))
992 return errmsg;
994 if (!simple_object_mach_o_write_segment (sobj, descriptor, nsects,
995 &errmsg, err))
996 return errmsg;
998 return NULL;
1001 /* Release the private data for an simple_object_write structure. */
1003 static void
1004 simple_object_mach_o_release_write (void *data)
1006 XDELETE (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