]> git.ipfire.org Git - thirdparty/gcc.git/blame - libiberty/simple-object-mach-o.c
i386.c (ix86_legitimize_address): Call convert_to_mode unconditionally.
[thirdparty/gcc.git] / libiberty / simple-object-mach-o.c
CommitLineData
1cfabf34 1/* simple-object-mach-o.c -- routines to manipulate Mach-O object files.
b20577ea 2 Copyright 2010, 2011 Free Software Foundation, Inc.
1cfabf34
ILT
3 Written by Ian Lance Taylor, Google.
4
5This program is free software; you can redistribute it and/or modify it
6under the terms of the GNU General Public License as published by the
7Free Software Foundation; either version 2, or (at your option) any
8later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, 51 Franklin Street - Fifth Floor,
18Boston, 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
48struct 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
61struct 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
85struct 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
98struct 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
115struct 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
132struct 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
149struct 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
b20577ea
IS
177/* A GNU-specific extension to wrap multiple sections using three
178 mach-o sections within a given segment. The section '__wrapper_sects'
179 is subdivided according to the index '__wrapper_index' and each sub
180 sect is named according to the names supplied in '__wrapper_names'. */
181
182#define GNU_WRAPPER_SECTS "__wrapper_sects"
183#define GNU_WRAPPER_INDEX "__wrapper_index"
184#define GNU_WRAPPER_NAMES "__wrapper_names"
185
1cfabf34
ILT
186/* Private data for an simple_object_read. */
187
188struct simple_object_mach_o_read
189{
190 /* User specified segment name. */
191 char *segment_name;
192 /* Magic number. */
193 unsigned int magic;
194 /* Whether this file is big-endian. */
195 int is_big_endian;
196 /* CPU type from header. */
197 unsigned int cputype;
198 /* CPU subtype from header. */
199 unsigned int cpusubtype;
200 /* Number of commands, from header. */
201 unsigned int ncmds;
202 /* Flags from header. */
203 unsigned int flags;
204 /* Reserved field from header, only used on 64-bit. */
205 unsigned int reserved;
206};
207
208/* Private data for an simple_object_attributes. */
209
210struct simple_object_mach_o_attributes
211{
212 /* Magic number. */
213 unsigned int magic;
214 /* Whether this file is big-endian. */
215 int is_big_endian;
216 /* CPU type from header. */
217 unsigned int cputype;
218 /* CPU subtype from header. */
219 unsigned int cpusubtype;
220 /* Flags from header. */
221 unsigned int flags;
222 /* Reserved field from header, only used on 64-bit. */
223 unsigned int reserved;
224};
225
b20577ea
IS
226/* See if we have a Mach-O MH_OBJECT file:
227
228 A standard MH_OBJECT (from as) will have three load commands:
229 0 - LC_SEGMENT/LC_SEGMENT64
230 1 - LC_SYMTAB
231 2 - LC_DYSYMTAB
232
233 The LC_SEGMENT/LC_SEGMENT64 will introduce a single anonymous segment
234 containing all the sections.
235
236 Files written by simple-object will have only the segment command
237 (no symbol tables). */
1cfabf34
ILT
238
239static void *
240simple_object_mach_o_match (
241 unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN],
242 int descriptor,
243 off_t offset,
244 const char *segment_name,
245 const char **errmsg,
246 int *err)
247{
248 unsigned int magic;
249 int is_big_endian;
250 unsigned int (*fetch_32) (const unsigned char *);
251 unsigned int filetype;
252 struct simple_object_mach_o_read *omr;
253 unsigned char buf[sizeof (struct mach_o_header_64)];
254 unsigned char *b;
255
256 magic = simple_object_fetch_big_32 (header);
257 if (magic == MACH_O_MH_MAGIC || magic == MACH_O_MH_MAGIC_64)
258 is_big_endian = 1;
259 else
260 {
261 magic = simple_object_fetch_little_32 (header);
262 if (magic == MACH_O_MH_MAGIC || magic == MACH_O_MH_MAGIC_64)
263 is_big_endian = 0;
264 else
265 {
266 *errmsg = NULL;
267 *err = 0;
268 return NULL;
269 }
270 }
271
272#ifndef UNSIGNED_64BIT_TYPE
273 if (magic == MACH_O_MH_MAGIC_64)
274 {
275 *errmsg = "64-bit Mach-O objects not supported";
276 *err = 0;
277 return NULL;
278 }
279#endif
280
281 /* We require the user to provide a segment name. This is
282 unfortunate but I don't see any good choices here. */
283
284 if (segment_name == NULL)
285 {
286 *errmsg = "Mach-O file found but no segment name specified";
287 *err = 0;
288 return NULL;
289 }
290
291 if (strlen (segment_name) > MACH_O_NAME_LEN)
292 {
293 *errmsg = "Mach-O segment name too long";
294 *err = 0;
295 return NULL;
296 }
297
298 /* The 32-bit and 64-bit headers are similar enough that we can use
299 the same code. */
300
301 fetch_32 = (is_big_endian
302 ? simple_object_fetch_big_32
303 : simple_object_fetch_little_32);
304
305 if (!simple_object_internal_read (descriptor, offset, buf,
306 (magic == MACH_O_MH_MAGIC
307 ? sizeof (struct mach_o_header_32)
308 : sizeof (struct mach_o_header_64)),
309 errmsg, err))
310 return NULL;
311
312 b = &buf[0];
313
314 filetype = (*fetch_32) (b + offsetof (struct mach_o_header_32, filetype));
315 if (filetype != MACH_O_MH_OBJECT)
316 {
317 *errmsg = "Mach-O file is not object file";
318 *err = 0;
319 return NULL;
320 }
321
322 omr = XNEW (struct simple_object_mach_o_read);
323 omr->segment_name = xstrdup (segment_name);
324 omr->magic = magic;
325 omr->is_big_endian = is_big_endian;
326 omr->cputype = (*fetch_32) (b + offsetof (struct mach_o_header_32, cputype));
327 omr->cpusubtype = (*fetch_32) (b
328 + offsetof (struct mach_o_header_32,
329 cpusubtype));
330 omr->ncmds = (*fetch_32) (b + offsetof (struct mach_o_header_32, ncmds));
331 omr->flags = (*fetch_32) (b + offsetof (struct mach_o_header_32, flags));
332 if (magic == MACH_O_MH_MAGIC)
333 omr->reserved = 0;
334 else
335 omr->reserved = (*fetch_32) (b
336 + offsetof (struct mach_o_header_64,
337 reserved));
338
339 return (void *) omr;
340}
341
342/* Get the file offset and size from a section header. */
343
344static void
345simple_object_mach_o_section_info (int is_big_endian, int is_32,
346 const unsigned char *sechdr, off_t *offset,
347 size_t *size)
348{
349 unsigned int (*fetch_32) (const unsigned char *);
350 ulong_type (*fetch_64) (const unsigned char *);
351
352 fetch_32 = (is_big_endian
353 ? simple_object_fetch_big_32
354 : simple_object_fetch_little_32);
355
356 fetch_64 = NULL;
357#ifdef UNSIGNED_64BIT_TYPE
358 fetch_64 = (is_big_endian
359 ? simple_object_fetch_big_64
360 : simple_object_fetch_little_64);
361#endif
362
363 if (is_32)
364 {
365 *offset = fetch_32 (sechdr
366 + offsetof (struct mach_o_section_32, offset));
367 *size = fetch_32 (sechdr
368 + offsetof (struct mach_o_section_32, size));
369 }
370 else
371 {
372 *offset = fetch_32 (sechdr
373 + offsetof (struct mach_o_section_64, offset));
374 *size = fetch_64 (sechdr
375 + offsetof (struct mach_o_section_64, size));
376 }
377}
378
b20577ea
IS
379/* Handle a segment in a Mach-O Object file.
380
381 This will callback to the function pfn for each "section found" the meaning
382 of which depends on gnu extensions to mach-o:
383
384 If we find mach-o sections (with the segment name as specified) which also
385 contain: a 'sects' wrapper, an index, and a name table, we expand this into
386 as many sections as are specified in the index. In this case, there will
387 be a callback for each of these.
388
389 We will also allow an extension that permits long names (more than 16
390 characters) to be used with mach-o. In this case, the section name has
391 a specific format embedding an index into a name table, and the file must
392 contain such name table.
393
394 Return 1 if we should continue, 0 if the caller should return. */
395
396#define SOMO_SECTS_PRESENT 0x01
397#define SOMO_INDEX_PRESENT 0x02
398#define SOMO_NAMES_PRESENT 0x04
399#define SOMO_LONGN_PRESENT 0x08
400#define SOMO_WRAPPING (SOMO_SECTS_PRESENT | SOMO_INDEX_PRESENT \
401 | SOMO_NAMES_PRESENT)
1cfabf34
ILT
402
403static int
404simple_object_mach_o_segment (simple_object_read *sobj, off_t offset,
405 const unsigned char *segbuf,
406 int (*pfn) (void *, const char *, off_t offset,
407 off_t length),
408 void *data,
409 const char **errmsg, int *err)
410{
411 struct simple_object_mach_o_read *omr =
412 (struct simple_object_mach_o_read *) sobj->data;
413 unsigned int (*fetch_32) (const unsigned char *);
414 int is_32;
415 size_t seghdrsize;
416 size_t sechdrsize;
417 size_t segname_offset;
418 size_t sectname_offset;
419 unsigned int nsects;
420 unsigned char *secdata;
421 unsigned int i;
b20577ea 422 unsigned int gnu_sections_found;
1cfabf34 423 unsigned int strtab_index;
b20577ea
IS
424 unsigned int index_index;
425 unsigned int nametab_index;
426 unsigned int sections_index;
1cfabf34 427 char *strtab;
b20577ea
IS
428 char *nametab;
429 unsigned char *index;
1cfabf34 430 size_t strtab_size;
b20577ea
IS
431 size_t nametab_size;
432 size_t index_size;
433 unsigned int n_wrapped_sects;
434 size_t wrapper_sect_size;
435 off_t wrapper_sect_offset;
1cfabf34
ILT
436
437 fetch_32 = (omr->is_big_endian
438 ? simple_object_fetch_big_32
439 : simple_object_fetch_little_32);
440
441 is_32 = omr->magic == MACH_O_MH_MAGIC;
442
443 if (is_32)
444 {
445 seghdrsize = sizeof (struct mach_o_segment_command_32);
446 sechdrsize = sizeof (struct mach_o_section_32);
447 segname_offset = offsetof (struct mach_o_section_32, segname);
448 sectname_offset = offsetof (struct mach_o_section_32, sectname);
449 nsects = (*fetch_32) (segbuf
450 + offsetof (struct mach_o_segment_command_32,
451 nsects));
452 }
453 else
454 {
455 seghdrsize = sizeof (struct mach_o_segment_command_64);
456 sechdrsize = sizeof (struct mach_o_section_64);
457 segname_offset = offsetof (struct mach_o_section_64, segname);
458 sectname_offset = offsetof (struct mach_o_section_64, sectname);
459 nsects = (*fetch_32) (segbuf
460 + offsetof (struct mach_o_segment_command_64,
461 nsects));
462 }
463
b20577ea
IS
464 /* Fetch the section headers from the segment command. */
465
1cfabf34
ILT
466 secdata = XNEWVEC (unsigned char, nsects * sechdrsize);
467 if (!simple_object_internal_read (sobj->descriptor, offset + seghdrsize,
468 secdata, nsects * sechdrsize, errmsg, err))
469 {
470 XDELETEVEC (secdata);
471 return 0;
472 }
473
b20577ea 474 /* Scan for special sections that signal GNU extensions to the format. */
1cfabf34 475
b20577ea
IS
476 gnu_sections_found = 0;
477 index_index = nsects;
478 sections_index = nsects;
479 strtab_index = nsects;
480 nametab_index = nsects;
1cfabf34
ILT
481 for (i = 0; i < nsects; ++i)
482 {
483 size_t nameoff;
484
485 nameoff = i * sechdrsize + segname_offset;
486 if (strcmp ((char *) secdata + nameoff, omr->segment_name) != 0)
487 continue;
b20577ea 488
1cfabf34 489 nameoff = i * sechdrsize + sectname_offset;
b20577ea
IS
490 if (strcmp ((char *) secdata + nameoff, GNU_WRAPPER_NAMES) == 0)
491 {
492 nametab_index = i;
493 gnu_sections_found |= SOMO_NAMES_PRESENT;
494 }
495 else if (strcmp ((char *) secdata + nameoff, GNU_WRAPPER_INDEX) == 0)
496 {
497 index_index = i;
498 gnu_sections_found |= SOMO_INDEX_PRESENT;
499 }
500 else if (strcmp ((char *) secdata + nameoff, GNU_WRAPPER_SECTS) == 0)
501 {
502 sections_index = i;
503 gnu_sections_found |= SOMO_SECTS_PRESENT;
504 }
505 else if (strcmp ((char *) secdata + nameoff, GNU_SECTION_NAMES) == 0)
506 {
507 strtab_index = i;
508 gnu_sections_found |= SOMO_LONGN_PRESENT;
509 }
1cfabf34
ILT
510 }
511
b20577ea
IS
512 /* If any of the special wrapper section components is present, then
513 they all should be. */
514
515 if ((gnu_sections_found & SOMO_WRAPPING) != 0)
1cfabf34 516 {
b20577ea
IS
517 off_t nametab_offset;
518 off_t index_offset;
519
520 if ((gnu_sections_found & SOMO_WRAPPING) != SOMO_WRAPPING)
521 {
522 *errmsg = "GNU Mach-o section wrapper: required section missing";
523 *err = 0; /* No useful errno. */
524 XDELETEVEC (secdata);
525 return 0;
526 }
527
528 /* Fetch the name table. */
529
530 simple_object_mach_o_section_info (omr->is_big_endian, is_32,
531 secdata + nametab_index * sechdrsize,
532 &nametab_offset, &nametab_size);
533 nametab = XNEWVEC (char, nametab_size);
534 if (!simple_object_internal_read (sobj->descriptor,
535 sobj->offset + nametab_offset,
536 (unsigned char *) nametab, nametab_size,
537 errmsg, err))
538 {
539 XDELETEVEC (nametab);
540 XDELETEVEC (secdata);
541 return 0;
542 }
543
544 /* Fetch the index. */
545
546 simple_object_mach_o_section_info (omr->is_big_endian, is_32,
547 secdata + index_index * sechdrsize,
548 &index_offset, &index_size);
549 index = XNEWVEC (unsigned char, index_size);
550 if (!simple_object_internal_read (sobj->descriptor,
551 sobj->offset + index_offset,
552 index, index_size,
553 errmsg, err))
554 {
555 XDELETEVEC (index);
556 XDELETEVEC (nametab);
557 XDELETEVEC (secdata);
558 return 0;
559 }
560
561 /* The index contains 4 unsigned ints per sub-section:
562 sub-section offset/length, sub-section name/length.
563 We fix this for both 32 and 64 bit mach-o for now, since
564 other fields limit the maximum size of an object to 4G. */
565 n_wrapped_sects = index_size / 16;
566
567 /* Get the parameters for the wrapper too. */
568 simple_object_mach_o_section_info (omr->is_big_endian, is_32,
569 secdata + sections_index * sechdrsize,
570 &wrapper_sect_offset,
571 &wrapper_sect_size);
1cfabf34
ILT
572 }
573 else
b20577ea
IS
574 {
575 index = NULL;
576 index_size = 0;
577 nametab = NULL;
578 nametab_size = 0;
579 n_wrapped_sects = 0;
580 }
581
582 /* If we have a long names section, fetch it. */
583
584 if ((gnu_sections_found & SOMO_LONGN_PRESENT) != 0)
1cfabf34
ILT
585 {
586 off_t strtab_offset;
587
588 simple_object_mach_o_section_info (omr->is_big_endian, is_32,
589 secdata + strtab_index * sechdrsize,
590 &strtab_offset, &strtab_size);
591 strtab = XNEWVEC (char, strtab_size);
592 if (!simple_object_internal_read (sobj->descriptor,
593 sobj->offset + strtab_offset,
594 (unsigned char *) strtab, strtab_size,
595 errmsg, err))
596 {
597 XDELETEVEC (strtab);
b20577ea
IS
598 XDELETEVEC (index);
599 XDELETEVEC (nametab);
1cfabf34
ILT
600 XDELETEVEC (secdata);
601 return 0;
602 }
603 }
b20577ea
IS
604 else
605 {
606 strtab = NULL;
607 strtab_size = 0;
608 strtab_index = nsects;
609 }
1cfabf34
ILT
610
611 /* Process the sections. */
612
613 for (i = 0; i < nsects; ++i)
614 {
615 const unsigned char *sechdr;
b20577ea 616 char namebuf[MACH_O_NAME_LEN * 2 + 2];
1cfabf34
ILT
617 char *name;
618 off_t secoffset;
619 size_t secsize;
b20577ea 620 int l;
1cfabf34 621
b20577ea
IS
622 sechdr = secdata + i * sechdrsize;
623
624 /* We've already processed the long section names. */
625
626 if ((gnu_sections_found & SOMO_LONGN_PRESENT) != 0
627 && i == strtab_index)
1cfabf34
ILT
628 continue;
629
b20577ea 630 /* We only act on the segment named. */
1cfabf34
ILT
631
632 if (strcmp ((char *) sechdr + segname_offset, omr->segment_name) != 0)
633 continue;
634
b20577ea 635 /* Process sections associated with the wrapper. */
1cfabf34 636
b20577ea 637 if ((gnu_sections_found & SOMO_WRAPPING) != 0)
1cfabf34 638 {
b20577ea
IS
639 if (i == nametab_index || i == index_index)
640 continue;
1cfabf34 641
b20577ea 642 if (i == sections_index)
1cfabf34 643 {
b20577ea
IS
644 unsigned int j;
645 for (j = 0; j < n_wrapped_sects; ++j)
1cfabf34 646 {
b20577ea
IS
647 unsigned int subsect_offset, subsect_length, name_offset;
648 subsect_offset = (*fetch_32) (index + 16 * j);
649 subsect_length = (*fetch_32) (index + 16 * j + 4);
650 name_offset = (*fetch_32) (index + 16 * j + 8);
651 /* We don't need the name_length yet. */
652
653 secoffset = wrapper_sect_offset + subsect_offset;
654 secsize = subsect_length;
655 name = nametab + name_offset;
656
657 if (!(*pfn) (data, name, secoffset, secsize))
658 {
659 *errmsg = NULL;
660 *err = 0;
661 XDELETEVEC (index);
662 XDELETEVEC (nametab);
663 XDELETEVEC (strtab);
664 XDELETEVEC (secdata);
665 return 0;
666 }
1cfabf34 667 }
b20577ea 668 continue;
1cfabf34
ILT
669 }
670 }
671
b20577ea
IS
672 if ((gnu_sections_found & SOMO_LONGN_PRESENT) != 0)
673 {
674 memcpy (namebuf, sechdr + sectname_offset, MACH_O_NAME_LEN);
675 namebuf[MACH_O_NAME_LEN] = '\0';
676
677 name = &namebuf[0];
678 if (strtab != NULL && name[0] == '_' && name[1] == '_')
679 {
680 unsigned long stringoffset;
681
682 if (sscanf (name + 2, "%08lX", &stringoffset) == 1)
683 {
684 if (stringoffset >= strtab_size)
685 {
686 *errmsg = "section name offset out of range";
687 *err = 0;
688 XDELETEVEC (index);
689 XDELETEVEC (nametab);
690 XDELETEVEC (strtab);
691 XDELETEVEC (secdata);
692 return 0;
693 }
694
695 name = strtab + stringoffset;
696 }
697 }
698 }
699 else
700 {
701 /* Otherwise, make a name like __segment,__section as per the
702 convention in mach-o asm. */
703 name = &namebuf[0];
704 memset (namebuf, 0, MACH_O_NAME_LEN * 2 + 2);
705 memcpy (namebuf, (char *) sechdr + segname_offset, MACH_O_NAME_LEN);
706 l = strlen (namebuf);
707 namebuf[l] = ',';
708 memcpy (namebuf + l + 1, (char *) sechdr + sectname_offset,
709 MACH_O_NAME_LEN);
710 }
711
1cfabf34
ILT
712 simple_object_mach_o_section_info (omr->is_big_endian, is_32, sechdr,
713 &secoffset, &secsize);
714
715 if (!(*pfn) (data, name, secoffset, secsize))
716 {
717 *errmsg = NULL;
718 *err = 0;
b20577ea
IS
719 XDELETEVEC (index);
720 XDELETEVEC (nametab);
1cfabf34
ILT
721 XDELETEVEC (strtab);
722 XDELETEVEC (secdata);
723 return 0;
724 }
725 }
726
b20577ea
IS
727 XDELETEVEC (index);
728 XDELETEVEC (nametab);
1cfabf34
ILT
729 XDELETEVEC (strtab);
730 XDELETEVEC (secdata);
731
732 return 1;
733}
734
735/* Find all sections in a Mach-O file. */
736
737static const char *
738simple_object_mach_o_find_sections (simple_object_read *sobj,
739 int (*pfn) (void *, const char *,
740 off_t offset, off_t length),
741 void *data,
742 int *err)
743{
744 struct simple_object_mach_o_read *omr =
745 (struct simple_object_mach_o_read *) sobj->data;
746 off_t offset;
747 size_t seghdrsize;
748 unsigned int (*fetch_32) (const unsigned char *);
749 const char *errmsg;
750 unsigned int i;
751
752 if (omr->magic == MACH_O_MH_MAGIC)
753 {
754 offset = sizeof (struct mach_o_header_32);
755 seghdrsize = sizeof (struct mach_o_segment_command_32);
756 }
757 else
758 {
759 offset = sizeof (struct mach_o_header_64);
760 seghdrsize = sizeof (struct mach_o_segment_command_64);
761 }
762
763 fetch_32 = (omr->is_big_endian
764 ? simple_object_fetch_big_32
765 : simple_object_fetch_little_32);
766
767 for (i = 0; i < omr->ncmds; ++i)
768 {
769 unsigned char loadbuf[sizeof (struct mach_o_load_command)];
770 unsigned int cmd;
771 unsigned int cmdsize;
772
773 if (!simple_object_internal_read (sobj->descriptor,
774 sobj->offset + offset,
775 loadbuf,
776 sizeof (struct mach_o_load_command),
777 &errmsg, err))
778 return errmsg;
779
780 cmd = (*fetch_32) (loadbuf + offsetof (struct mach_o_load_command, cmd));
781 cmdsize = (*fetch_32) (loadbuf
782 + offsetof (struct mach_o_load_command, cmdsize));
783
784 if (cmd == MACH_O_LC_SEGMENT || cmd == MACH_O_LC_SEGMENT_64)
785 {
786 unsigned char segbuf[sizeof (struct mach_o_segment_command_64)];
787 int r;
788
789 if (!simple_object_internal_read (sobj->descriptor,
790 sobj->offset + offset,
791 segbuf, seghdrsize, &errmsg, err))
792 return errmsg;
793
794 r = simple_object_mach_o_segment (sobj, offset, segbuf, pfn,
795 data, &errmsg, err);
796 if (!r)
797 return errmsg;
798 }
799
800 offset += cmdsize;
801 }
802
803 return NULL;
804}
805
806/* Fetch the attributes for an simple_object_read. */
807
808static void *
809simple_object_mach_o_fetch_attributes (simple_object_read *sobj,
810 const char **errmsg ATTRIBUTE_UNUSED,
811 int *err ATTRIBUTE_UNUSED)
812{
813 struct simple_object_mach_o_read *omr =
814 (struct simple_object_mach_o_read *) sobj->data;
815 struct simple_object_mach_o_attributes *ret;
816
817 ret = XNEW (struct simple_object_mach_o_attributes);
818 ret->magic = omr->magic;
819 ret->is_big_endian = omr->is_big_endian;
820 ret->cputype = omr->cputype;
821 ret->cpusubtype = omr->cpusubtype;
822 ret->flags = omr->flags;
823 ret->reserved = omr->reserved;
824 return ret;
825}
826
827/* Release the private data for an simple_object_read. */
828
829static void
830simple_object_mach_o_release_read (void *data)
831{
832 struct simple_object_mach_o_read *omr =
833 (struct simple_object_mach_o_read *) data;
834
835 free (omr->segment_name);
836 XDELETE (omr);
837}
838
839/* Compare two attributes structures. */
840
841static const char *
d82f74d3 842simple_object_mach_o_attributes_merge (void *todata, void *fromdata, int *err)
1cfabf34 843{
d82f74d3
ILT
844 struct simple_object_mach_o_attributes *to =
845 (struct simple_object_mach_o_attributes *) todata;
846 struct simple_object_mach_o_attributes *from =
847 (struct simple_object_mach_o_attributes *) fromdata;
848
849 if (to->magic != from->magic
850 || to->is_big_endian != from->is_big_endian
851 || to->cputype != from->cputype)
1cfabf34
ILT
852 {
853 *err = 0;
854 return "Mach-O object format mismatch";
855 }
856 return NULL;
857}
858
859/* Release the private data for an attributes structure. */
860
861static void
862simple_object_mach_o_release_attributes (void *data)
863{
864 XDELETE (data);
865}
866
867/* Prepare to write out a file. */
868
869static void *
870simple_object_mach_o_start_write (void *attributes_data,
871 const char **errmsg ATTRIBUTE_UNUSED,
872 int *err ATTRIBUTE_UNUSED)
873{
874 struct simple_object_mach_o_attributes *attrs =
875 (struct simple_object_mach_o_attributes *) attributes_data;
876 struct simple_object_mach_o_attributes *ret;
877
878 /* We're just going to record the attributes, but we need to make a
879 copy because the user may delete them. */
880 ret = XNEW (struct simple_object_mach_o_attributes);
881 *ret = *attrs;
882 return ret;
883}
884
885/* Write out the header of a Mach-O file. */
886
887static int
888simple_object_mach_o_write_header (simple_object_write *sobj, int descriptor,
889 size_t nsects, const char **errmsg,
890 int *err)
891{
892 struct simple_object_mach_o_attributes *attrs =
893 (struct simple_object_mach_o_attributes *) sobj->data;
894 void (*set_32) (unsigned char *, unsigned int);
895 unsigned char hdrbuf[sizeof (struct mach_o_header_64)];
896 unsigned char *hdr;
897 size_t wrsize;
898
899 set_32 = (attrs->is_big_endian
900 ? simple_object_set_big_32
901 : simple_object_set_little_32);
902
903 memset (hdrbuf, 0, sizeof hdrbuf);
904
905 /* The 32-bit and 64-bit headers start out the same. */
906
907 hdr = &hdrbuf[0];
908 set_32 (hdr + offsetof (struct mach_o_header_32, magic), attrs->magic);
909 set_32 (hdr + offsetof (struct mach_o_header_32, cputype), attrs->cputype);
910 set_32 (hdr + offsetof (struct mach_o_header_32, cpusubtype),
911 attrs->cpusubtype);
912 set_32 (hdr + offsetof (struct mach_o_header_32, filetype), MACH_O_MH_OBJECT);
913 set_32 (hdr + offsetof (struct mach_o_header_32, ncmds), 1);
914 set_32 (hdr + offsetof (struct mach_o_header_32, flags), attrs->flags);
915 if (attrs->magic == MACH_O_MH_MAGIC)
916 {
917 wrsize = sizeof (struct mach_o_header_32);
918 set_32 (hdr + offsetof (struct mach_o_header_32, sizeofcmds),
919 (sizeof (struct mach_o_segment_command_32)
920 + nsects * sizeof (struct mach_o_section_32)));
921 }
922 else
923 {
924 set_32 (hdr + offsetof (struct mach_o_header_64, sizeofcmds),
925 (sizeof (struct mach_o_segment_command_64)
926 + nsects * sizeof (struct mach_o_section_64)));
927 set_32 (hdr + offsetof (struct mach_o_header_64, reserved),
928 attrs->reserved);
929 wrsize = sizeof (struct mach_o_header_64);
930 }
931
932 return simple_object_internal_write (descriptor, 0, hdrbuf, wrsize,
933 errmsg, err);
934}
935
936/* Write a Mach-O section header. */
937
938static int
939simple_object_mach_o_write_section_header (simple_object_write *sobj,
940 int descriptor,
941 size_t sechdr_offset,
b20577ea
IS
942 const char *name, const char *segn,
943 size_t secaddr, size_t secsize,
944 size_t offset, unsigned int align,
1cfabf34
ILT
945 const char **errmsg, int *err)
946{
947 struct simple_object_mach_o_attributes *attrs =
948 (struct simple_object_mach_o_attributes *) sobj->data;
949 void (*set_32) (unsigned char *, unsigned int);
950 unsigned char hdrbuf[sizeof (struct mach_o_section_64)];
951 unsigned char *hdr;
952 size_t sechdrsize;
953
954 set_32 = (attrs->is_big_endian
955 ? simple_object_set_big_32
956 : simple_object_set_little_32);
957
958 memset (hdrbuf, 0, sizeof hdrbuf);
959
960 hdr = &hdrbuf[0];
961 if (attrs->magic == MACH_O_MH_MAGIC)
962 {
963 strncpy ((char *) hdr + offsetof (struct mach_o_section_32, sectname),
964 name, MACH_O_NAME_LEN);
965 strncpy ((char *) hdr + offsetof (struct mach_o_section_32, segname),
b20577ea 966 segn, MACH_O_NAME_LEN);
1cfabf34
ILT
967 set_32 (hdr + offsetof (struct mach_o_section_32, addr), secaddr);
968 set_32 (hdr + offsetof (struct mach_o_section_32, size), secsize);
969 set_32 (hdr + offsetof (struct mach_o_section_32, offset), offset);
970 set_32 (hdr + offsetof (struct mach_o_section_32, align), align);
971 /* reloff left as zero. */
972 /* nreloc left as zero. */
973 set_32 (hdr + offsetof (struct mach_o_section_32, flags),
974 MACH_O_S_ATTR_DEBUG);
975 /* reserved1 left as zero. */
976 /* reserved2 left as zero. */
977 sechdrsize = sizeof (struct mach_o_section_32);
978 }
979 else
980 {
981#ifdef UNSIGNED_64BIT_TYPE
982 void (*set_64) (unsigned char *, ulong_type);
983
984 set_64 = (attrs->is_big_endian
985 ? simple_object_set_big_64
986 : simple_object_set_little_64);
987
988 strncpy ((char *) hdr + offsetof (struct mach_o_section_64, sectname),
989 name, MACH_O_NAME_LEN);
990 strncpy ((char *) hdr + offsetof (struct mach_o_section_64, segname),
b20577ea 991 segn, MACH_O_NAME_LEN);
1cfabf34
ILT
992 set_64 (hdr + offsetof (struct mach_o_section_64, addr), secaddr);
993 set_64 (hdr + offsetof (struct mach_o_section_64, size), secsize);
994 set_32 (hdr + offsetof (struct mach_o_section_64, offset), offset);
995 set_32 (hdr + offsetof (struct mach_o_section_64, align), align);
996 /* reloff left as zero. */
997 /* nreloc left as zero. */
998 set_32 (hdr + offsetof (struct mach_o_section_64, flags),
999 MACH_O_S_ATTR_DEBUG);
1000 /* reserved1 left as zero. */
1001 /* reserved2 left as zero. */
1002 /* reserved3 left as zero. */
1003#endif
1004 sechdrsize = sizeof (struct mach_o_section_64);
1005 }
1006
1007 return simple_object_internal_write (descriptor, sechdr_offset, hdr,
1008 sechdrsize, errmsg, err);
1009}
1010
b20577ea
IS
1011/* Write out the single (anonymous) segment containing the sections of a Mach-O
1012 Object file.
1013
1014 As a GNU extension to mach-o, when the caller specifies a segment name in
1015 sobj->segment_name, all the sections passed will be output under a single
1016 mach-o section header. The caller's sections are indexed within this
1017 'wrapper' section by a table stored in a second mach-o section. Finally,
1018 arbitrary length section names are permitted by the extension and these are
1019 stored in a table in a third mach-o section.
1020
1021 Note that this is only likely to make any sense for the __GNU_LTO segment
1022 at present.
1023
1024 If the wrapper extension is not in force, we assume that the section name
1025 is in the form __SEGMENT_NAME,__section_name as per Mach-O asm. */
1cfabf34
ILT
1026
1027static int
1028simple_object_mach_o_write_segment (simple_object_write *sobj, int descriptor,
b20577ea 1029 size_t *nsects, const char **errmsg,
1cfabf34
ILT
1030 int *err)
1031{
1032 struct simple_object_mach_o_attributes *attrs =
1033 (struct simple_object_mach_o_attributes *) sobj->data;
1034 void (*set_32) (unsigned char *, unsigned int);
1035 size_t hdrsize;
1036 size_t seghdrsize;
1037 size_t sechdrsize;
1038 size_t cmdsize;
1039 size_t offset;
1040 size_t sechdr_offset;
1041 size_t secaddr;
1042 unsigned int name_offset;
1043 simple_object_write_section *section;
1044 unsigned char hdrbuf[sizeof (struct mach_o_segment_command_64)];
1045 unsigned char *hdr;
b20577ea
IS
1046 size_t nsects_in;
1047 unsigned int *index;
1048 char *snames;
1049 unsigned int sect;
1cfabf34
ILT
1050
1051 set_32 = (attrs->is_big_endian
1052 ? simple_object_set_big_32
1053 : simple_object_set_little_32);
1054
1055 /* Write out the sections first. */
1056
1057 if (attrs->magic == MACH_O_MH_MAGIC)
1058 {
1059 hdrsize = sizeof (struct mach_o_header_32);
1060 seghdrsize = sizeof (struct mach_o_segment_command_32);
1061 sechdrsize = sizeof (struct mach_o_section_32);
1062 }
1063 else
1064 {
1065 hdrsize = sizeof (struct mach_o_header_64);
1066 seghdrsize = sizeof (struct mach_o_segment_command_64);
1067 sechdrsize = sizeof (struct mach_o_section_64);
1068 }
1069
b20577ea
IS
1070 name_offset = 0;
1071 *nsects = nsects_in = 0;
1072
1073 /* Count the number of sections we start with. */
1074
1075 for (section = sobj->sections; section != NULL; section = section->next)
1076 nsects_in++;
1077
1078 if (sobj->segment_name != NULL)
1079 {
1080 /* We will only write 3 sections: wrapped data, index and names. */
1081
1082 *nsects = 3;
1083
1084 /* The index has four entries per wrapped section:
1085 Section Offset, length, Name offset, length.
1086 Where the offsets are based at the start of the wrapper and name
1087 sections respectively.
1088 The values are stored as 32 bit int for both 32 and 64 bit mach-o
1089 since the size of a mach-o MH_OBJECT cannot exceed 4G owing to
1090 other constraints. */
1091
1092 index = XNEWVEC (unsigned int, nsects_in * 4);
1093
1094 /* We now need to figure out the size of the names section. This just
1095 stores the names as null-terminated c strings, packed without any
1096 alignment padding. */
1097
1098 for (section = sobj->sections, sect = 0; section != NULL;
1099 section = section->next, sect++)
1100 {
1101 index[sect*4+2] = name_offset;
1102 index[sect*4+3] = strlen (section->name) + 1;
1103 name_offset += strlen (section->name) + 1;
1104 }
1105 snames = XNEWVEC (char, name_offset);
1106 }
1107 else
1108 {
1109 *nsects = nsects_in;
1110 index = NULL;
1111 snames = NULL;
1112 }
1113
1cfabf34 1114 sechdr_offset = hdrsize + seghdrsize;
b20577ea 1115 cmdsize = seghdrsize + *nsects * sechdrsize;
1cfabf34 1116 offset = hdrsize + cmdsize;
1cfabf34
ILT
1117 secaddr = 0;
1118
b20577ea
IS
1119 for (section = sobj->sections, sect = 0;
1120 section != NULL; section = section->next, sect++)
1cfabf34
ILT
1121 {
1122 size_t mask;
1123 size_t new_offset;
1124 size_t secsize;
1125 struct simple_object_write_section_buffer *buffer;
1cfabf34
ILT
1126
1127 mask = (1U << section->align) - 1;
1128 new_offset = offset + mask;
1129 new_offset &= ~ mask;
1130 while (new_offset > offset)
1131 {
1132 unsigned char zeroes[16];
1133 size_t write;
1134
1135 memset (zeroes, 0, sizeof zeroes);
1136 write = new_offset - offset;
1137 if (write > sizeof zeroes)
1138 write = sizeof zeroes;
1139 if (!simple_object_internal_write (descriptor, offset, zeroes, write,
1140 errmsg, err))
1141 return 0;
1142 offset += write;
1143 }
1144
1145 secsize = 0;
1146 for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
1147 {
1148 if (!simple_object_internal_write (descriptor, offset + secsize,
1149 ((const unsigned char *)
1150 buffer->buffer),
1151 buffer->size, errmsg, err))
1152 return 0;
1153 secsize += buffer->size;
1154 }
1155
b20577ea
IS
1156 if (sobj->segment_name != NULL)
1157 {
1158 index[sect*4+0] = (unsigned int) offset;
1159 index[sect*4+1] = secsize;
1160 /* Stash the section name in our table. */
1161 memcpy (snames + index[sect * 4 + 2], section->name,
1162 index[sect * 4 + 3]);
1163 }
1164 else
1165 {
1166 char namebuf[MACH_O_NAME_LEN + 1];
1167 char segnbuf[MACH_O_NAME_LEN + 1];
1168 char *comma;
1169
1170 /* Try to extract segment,section from the input name. */
1171
1172 memset (namebuf, 0, sizeof namebuf);
1173 memset (segnbuf, 0, sizeof segnbuf);
1174 comma = strchr (section->name, ',');
1175 if (comma != NULL)
1176 {
1177 int len = comma - section->name;
1178 len = len > MACH_O_NAME_LEN ? MACH_O_NAME_LEN : len;
1179 strncpy (namebuf, section->name, len);
1180 strncpy (segnbuf, comma + 1, MACH_O_NAME_LEN);
1181 }
1182 else /* just try to copy the name, leave segment blank. */
1183 strncpy (namebuf, section->name, MACH_O_NAME_LEN);
1184
1185 if (!simple_object_mach_o_write_section_header (sobj, descriptor,
1186 sechdr_offset,
1187 namebuf, segnbuf,
1188 secaddr, secsize,
1189 offset,
1190 section->align,
1191 errmsg, err))
1192 return 0;
1193 sechdr_offset += sechdrsize;
1194 }
1195
1196 offset += secsize;
1197 secaddr += secsize;
1198 }
1199
1200 if (sobj->segment_name != NULL)
1201 {
1202 size_t secsize;
1203 unsigned int i;
1204
1205 /* Write the section header for the wrapper. */
1206 /* Account for any initial aligment - which becomes the alignment for this
1207 created section. */
1208
1209 secsize = (offset - index[0]);
1cfabf34 1210 if (!simple_object_mach_o_write_section_header (sobj, descriptor,
b20577ea
IS
1211 sechdr_offset,
1212 GNU_WRAPPER_SECTS,
1213 sobj->segment_name,
1214 0 /*secaddr*/,
1215 secsize, index[0],
1216 sobj->sections->align,
1cfabf34
ILT
1217 errmsg, err))
1218 return 0;
1219
b20577ea
IS
1220 /* Subtract the wrapper section start from the begining of each sub
1221 section. */
1222
1223 for (i = 1; i < nsects_in; ++i)
1224 index[4 * i] -= index[0];
1225 index[0] = 0;
1226
1cfabf34 1227 sechdr_offset += sechdrsize;
1cfabf34 1228
b20577ea
IS
1229 /* Write out the section names.
1230 ... the header ...
1231 name_offset contains the length of the section. It is not aligned. */
1cfabf34 1232
b20577ea
IS
1233 if (!simple_object_mach_o_write_section_header (sobj, descriptor,
1234 sechdr_offset,
1235 GNU_WRAPPER_NAMES,
1236 sobj->segment_name,
1237 0 /*secaddr*/,
1238 name_offset,
1239 offset,
1240 0, errmsg, err))
1241 return 0;
1cfabf34 1242
b20577ea
IS
1243 /* ... and the content.. */
1244 if (!simple_object_internal_write (descriptor, offset,
1245 (const unsigned char *) snames,
1246 name_offset, errmsg, err))
1247 return 0;
1248
1249 sechdr_offset += sechdrsize;
1250 secaddr += name_offset;
1251 offset += name_offset;
1252
1253 /* Now do the index, we'll align this to 4 bytes although the read code
1254 will handle unaligned. */
1255
1256 offset += 3;
1257 offset &= ~0x03;
1258 if (!simple_object_mach_o_write_section_header (sobj, descriptor,
1259 sechdr_offset,
1260 GNU_WRAPPER_INDEX,
1261 sobj->segment_name,
1262 0 /*secaddr*/,
1263 nsects_in * 16,
1264 offset,
1265 2, errmsg, err))
1266 return 0;
1cfabf34 1267
b20577ea 1268 /* ... and the content.. */
1cfabf34 1269 if (!simple_object_internal_write (descriptor, offset,
b20577ea
IS
1270 (const unsigned char *) index,
1271 nsects_in*16, errmsg, err))
1cfabf34 1272 return 0;
b20577ea
IS
1273
1274 XDELETEVEC (index);
1275 XDELETEVEC (snames);
1cfabf34
ILT
1276 }
1277
1278 /* Write out the segment header. */
1279
1280 memset (hdrbuf, 0, sizeof hdrbuf);
1281
1282 hdr = &hdrbuf[0];
1283 if (attrs->magic == MACH_O_MH_MAGIC)
1284 {
1285 set_32 (hdr + offsetof (struct mach_o_segment_command_32, cmd),
1286 MACH_O_LC_SEGMENT);
1287 set_32 (hdr + offsetof (struct mach_o_segment_command_32, cmdsize),
1288 cmdsize);
b20577ea
IS
1289 /* MH_OBJECTS have a single, anonymous, segment - so the segment name
1290 is left empty. */
1cfabf34
ILT
1291 /* vmaddr left as zero. */
1292 /* vmsize left as zero. */
1293 set_32 (hdr + offsetof (struct mach_o_segment_command_32, fileoff),
1294 hdrsize + cmdsize);
1295 set_32 (hdr + offsetof (struct mach_o_segment_command_32, filesize),
1296 offset - (hdrsize + cmdsize));
1297 /* maxprot left as zero. */
1298 /* initprot left as zero. */
1299 set_32 (hdr + offsetof (struct mach_o_segment_command_32, nsects),
b20577ea 1300 *nsects);
1cfabf34
ILT
1301 /* flags left as zero. */
1302 }
1303 else
1304 {
1305#ifdef UNSIGNED_64BIT_TYPE
1306 void (*set_64) (unsigned char *, ulong_type);
1307
1308 set_64 = (attrs->is_big_endian
1309 ? simple_object_set_big_64
1310 : simple_object_set_little_64);
1311
1312 set_32 (hdr + offsetof (struct mach_o_segment_command_64, cmd),
1313 MACH_O_LC_SEGMENT);
1314 set_32 (hdr + offsetof (struct mach_o_segment_command_64, cmdsize),
1315 cmdsize);
b20577ea
IS
1316 /* MH_OBJECTS have a single, anonymous, segment - so the segment name
1317 is left empty. */
1cfabf34
ILT
1318 /* vmaddr left as zero. */
1319 /* vmsize left as zero. */
1320 set_64 (hdr + offsetof (struct mach_o_segment_command_64, fileoff),
1321 hdrsize + cmdsize);
1322 set_64 (hdr + offsetof (struct mach_o_segment_command_64, filesize),
1323 offset - (hdrsize + cmdsize));
1324 /* maxprot left as zero. */
1325 /* initprot left as zero. */
1326 set_32 (hdr + offsetof (struct mach_o_segment_command_64, nsects),
b20577ea 1327 *nsects);
1cfabf34
ILT
1328 /* flags left as zero. */
1329#endif
1330 }
1331
1332 return simple_object_internal_write (descriptor, hdrsize, hdr, seghdrsize,
1333 errmsg, err);
1334}
1335
1336/* Write out a complete Mach-O file. */
1337
1338static const char *
1339simple_object_mach_o_write_to_file (simple_object_write *sobj, int descriptor,
1340 int *err)
1341{
b20577ea 1342 size_t nsects = 0;
1cfabf34
ILT
1343 const char *errmsg;
1344
b20577ea
IS
1345 if (!simple_object_mach_o_write_segment (sobj, descriptor, &nsects,
1346 &errmsg, err))
1347 return errmsg;
1cfabf34
ILT
1348
1349 if (!simple_object_mach_o_write_header (sobj, descriptor, nsects,
1350 &errmsg, err))
1351 return errmsg;
1352
1cfabf34
ILT
1353 return NULL;
1354}
1355
1356/* Release the private data for an simple_object_write structure. */
1357
1358static void
1359simple_object_mach_o_release_write (void *data)
1360{
1361 XDELETE (data);
1362}
1363
1364/* The Mach-O functions. */
1365
1366const struct simple_object_functions simple_object_mach_o_functions =
1367{
1368 simple_object_mach_o_match,
1369 simple_object_mach_o_find_sections,
1370 simple_object_mach_o_fetch_attributes,
1371 simple_object_mach_o_release_read,
d82f74d3 1372 simple_object_mach_o_attributes_merge,
1cfabf34
ILT
1373 simple_object_mach_o_release_attributes,
1374 simple_object_mach_o_start_write,
1375 simple_object_mach_o_write_to_file,
1376 simple_object_mach_o_release_write
1377};