Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5191 serge 1
/* simple-object-mach-o.c -- routines to manipulate Mach-O object files.
2
   Copyright 2010, 2011, 2013 Free Software Foundation, Inc.
3
   Written by Ian Lance Taylor, Google.
4
 
5
This program is free software; you can redistribute it and/or modify it
6
under the terms of the GNU General Public License as published by the
7
Free Software Foundation; either version 2, or (at your option) any
8
later version.
9
 
10
This program is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
GNU General Public License for more details.
14
 
15
You should have received a copy of the GNU General Public License
16
along with this program; if not, write to the Free Software
17
Foundation, 51 Franklin Street - Fifth Floor,
18
Boston, MA 02110-1301, USA.  */
19
 
20
#include "config.h"
21
#include "libiberty.h"
22
#include "simple-object.h"
23
 
24
#include 
25
 
26
#ifdef HAVE_STDLIB_H
27
#include 
28
#endif
29
 
30
#ifdef HAVE_STDINT_H
31
#include 
32
#endif
33
 
34
#ifdef HAVE_STRING_H
35
#include 
36
#endif
37
 
38
#ifdef HAVE_INTTYPES_H
39
#include 
40
#endif
41
 
42
#include "simple-object-common.h"
43
 
44
/* Mach-O structures and constants.  */
45
 
46
/* Mach-O header (32-bit version).  */
47
 
48
struct mach_o_header_32
49
{
50
  unsigned char magic[4];	/* Magic number.  */
51
  unsigned char cputype[4];	/* CPU that this object is for.  */
52
  unsigned char cpusubtype[4];	/* CPU subtype.  */
53
  unsigned char filetype[4];	/* Type of file.  */
54
  unsigned char ncmds[4];	/* Number of load commands.  */
55
  unsigned char sizeofcmds[4];	/* Total size of load commands.  */
56
  unsigned char flags[4];	/* Flags for special featues.  */
57
};
58
 
59
/* Mach-O header (64-bit version).  */
60
 
61
struct mach_o_header_64
62
{
63
  unsigned char magic[4];	/* Magic number.  */
64
  unsigned char cputype[4];	/* CPU that this object is for.  */
65
  unsigned char cpusubtype[4];	/* CPU subtype.  */
66
  unsigned char filetype[4];	/* Type of file.  */
67
  unsigned char ncmds[4];	/* Number of load commands.  */
68
  unsigned char sizeofcmds[4];	/* Total size of load commands.  */
69
  unsigned char flags[4];	/* Flags for special featues.  */
70
  unsigned char reserved[4];	/* Reserved.  Duh.  */
71
};
72
 
73
/* For magic field in header.  */
74
 
75
#define MACH_O_MH_MAGIC			0xfeedface
76
#define MACH_O_MH_MAGIC_64		0xfeedfacf
77
 
78
/* For filetype field in header.  */
79
 
80
#define MACH_O_MH_OBJECT		0x01
81
 
82
/* A Mach-O file is a list of load commands.  This is the header of a
83
   load command.  */
84
 
85
struct mach_o_load_command
86
{
87
  unsigned char cmd[4];		/* The type of load command.  */
88
  unsigned char cmdsize[4];	/* Size in bytes of entire command.  */
89
};
90
 
91
/* For cmd field in load command.   */
92
 
93
#define MACH_O_LC_SEGMENT		0x01
94
#define MACH_O_LC_SEGMENT_64		0x19
95
 
96
/* LC_SEGMENT load command.  */
97
 
98
struct mach_o_segment_command_32
99
{
100
  unsigned char cmd[4];		/* The type of load command (LC_SEGMENT).  */
101
  unsigned char cmdsize[4];	/* Size in bytes of entire command.  */
102
  unsigned char segname[16];	/* Name of this segment.  */
103
  unsigned char vmaddr[4];	/* Virtual memory address of this segment.  */
104
  unsigned char vmsize[4];	/* Size there, in bytes.  */
105
  unsigned char fileoff[4];	/* Offset in bytes of the data to be mapped.  */
106
  unsigned char filesize[4];	/* Size in bytes on disk.  */
107
  unsigned char maxprot[4];	/* Maximum permitted vmem protection.  */
108
  unsigned char initprot[4];	/* Initial vmem protection.  */
109
  unsigned char nsects[4];	/* Number of sections in this segment.  */
110
  unsigned char flags[4];	/* Flags that affect the loading.  */
111
};
112
 
113
/* LC_SEGMENT_64 load command.  */
114
 
115
struct mach_o_segment_command_64
116
{
117
  unsigned char cmd[4];		/* The type of load command (LC_SEGMENT_64).  */
118
  unsigned char cmdsize[4];	/* Size in bytes of entire command.  */
119
  unsigned char segname[16];	/* Name of this segment.  */
120
  unsigned char vmaddr[8];	/* Virtual memory address of this segment.  */
121
  unsigned char vmsize[8];	/* Size there, in bytes.  */
122
  unsigned char fileoff[8];	/* Offset in bytes of the data to be mapped.  */
123
  unsigned char filesize[8];	/* Size in bytes on disk.  */
124
  unsigned char maxprot[4];	/* Maximum permitted vmem protection.  */
125
  unsigned char initprot[4];	/* Initial vmem protection.  */
126
  unsigned char nsects[4];	/* Number of sections in this segment.  */
127
  unsigned char flags[4];	/* Flags that affect the loading.  */
128
};
129
 
130
/* 32-bit section header.  */
131
 
132
struct mach_o_section_32
133
{
134
  unsigned char sectname[16];	/* Section name.  */
135
  unsigned char segname[16];	/* Segment that the section belongs to.  */
136
  unsigned char addr[4];	/* Address of this section in memory.  */
137
  unsigned char size[4];	/* Size in bytes of this section.  */
138
  unsigned char offset[4];	/* File offset of this section.  */
139
  unsigned char align[4];	/* log2 of this section's alignment.  */
140
  unsigned char reloff[4];	/* File offset of this section's relocs.  */
141
  unsigned char nreloc[4];	/* Number of relocs for this section.  */
142
  unsigned char flags[4];	/* Section flags/attributes.  */
143
  unsigned char reserved1[4];
144
  unsigned char reserved2[4];
145
};
146
 
147
/* 64-bit section header.  */
148
 
149
struct mach_o_section_64
150
{
151
  unsigned char sectname[16];	/* Section name.  */
152
  unsigned char segname[16];	/* Segment that the section belongs to.  */
153
  unsigned char addr[8];	/* Address of this section in memory.  */
154
  unsigned char size[8];	/* Size in bytes of this section.  */
155
  unsigned char offset[4];	/* File offset of this section.  */
156
  unsigned char align[4];	/* log2 of this section's alignment.  */
157
  unsigned char reloff[4];	/* File offset of this section's relocs.  */
158
  unsigned char nreloc[4];	/* Number of relocs for this section.  */
159
  unsigned char flags[4];	/* Section flags/attributes.  */
160
  unsigned char reserved1[4];
161
  unsigned char reserved2[4];
162
  unsigned char reserved3[4];
163
};
164
 
165
/* Flags for Mach-O sections.  */
166
 
167
#define MACH_O_S_ATTR_DEBUG			0x02000000
168
 
169
/* The length of a segment or section name.  */
170
 
171
#define MACH_O_NAME_LEN (16)
172
 
173
/* A GNU specific extension for long section names.  */
174
 
175
#define GNU_SECTION_NAMES "__section_names"
176
 
177
/* 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
 
186
/* Private data for an simple_object_read.  */
187
 
188
struct 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
 
210
struct 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
 
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
 
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).  */
238
 
239
static void *
240
simple_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
 
344
static void
345
simple_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
 
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)
402
 
403
static int
404
simple_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;
422
  unsigned int gnu_sections_found;
423
  unsigned int strtab_index;
424
  unsigned int index_index;
425
  unsigned int nametab_index;
426
  unsigned int sections_index;
427
  char *strtab;
428
  char *nametab;
429
  unsigned char *index;
430
  size_t strtab_size;
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 = 0;
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
 
464
  /* Fetch the section headers from the segment command.  */
465
 
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
 
474
  /* Scan for special sections that signal GNU extensions to the format.  */
475
 
476
  gnu_sections_found = 0;
477
  index_index = nsects;
478
  sections_index = nsects;
479
  strtab_index = nsects;
480
  nametab_index = nsects;
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;
488
 
489
      nameoff = i * sechdrsize + sectname_offset;
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
	}
510
    }
511
 
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)
516
    {
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);
572
    }
573
  else
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)
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);
598
	  XDELETEVEC (index);
599
	  XDELETEVEC (nametab);
600
	  XDELETEVEC (secdata);
601
	  return 0;
602
	}
603
    }
604
  else
605
    {
606
      strtab = NULL;
607
      strtab_size = 0;
608
      strtab_index = nsects;
609
    }
610
 
611
  /* Process the sections.  */
612
 
613
  for (i = 0; i < nsects; ++i)
614
    {
615
      const unsigned char *sechdr;
616
      char namebuf[MACH_O_NAME_LEN * 2 + 2];
617
      char *name;
618
      off_t secoffset;
619
      size_t secsize;
620
      int l;
621
 
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)
628
	continue;
629
 
630
      /* We only act on the segment named.  */
631
 
632
      if (strcmp ((char *) sechdr + segname_offset, omr->segment_name) != 0)
633
	continue;
634
 
635
      /* Process sections associated with the wrapper.  */
636
 
637
      if ((gnu_sections_found & SOMO_WRAPPING) != 0)
638
	{
639
	  if (i == nametab_index || i == index_index)
640
	    continue;
641
 
642
	  if (i == sections_index)
643
	    {
644
	      unsigned int j;
645
	      for (j = 0; j < n_wrapped_sects; ++j)
646
		{
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
		    }
667
		}
668
	      continue;
669
	    }
670
	}
671
 
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
	  memcpy (namebuf, (char *) sechdr + segname_offset, MACH_O_NAME_LEN);
705
	  namebuf[MACH_O_NAME_LEN] = '\0';
706
	  l = strlen (namebuf);
707
	  namebuf[l] = ',';
708
	  memcpy (namebuf + l + 1, (char *) sechdr + sectname_offset,
709
		  MACH_O_NAME_LEN);
710
	  namebuf[l + 1 + MACH_O_NAME_LEN] = '\0';
711
	}
712
 
713
      simple_object_mach_o_section_info (omr->is_big_endian, is_32, sechdr,
714
					 &secoffset, &secsize);
715
 
716
      if (!(*pfn) (data, name, secoffset, secsize))
717
	{
718
	  *errmsg = NULL;
719
	  *err = 0;
720
	  XDELETEVEC (index);
721
	  XDELETEVEC (nametab);
722
	  XDELETEVEC (strtab);
723
	  XDELETEVEC (secdata);
724
	  return 0;
725
	}
726
    }
727
 
728
  XDELETEVEC (index);
729
  XDELETEVEC (nametab);
730
  XDELETEVEC (strtab);
731
  XDELETEVEC (secdata);
732
 
733
  return 1;
734
}
735
 
736
/* Find all sections in a Mach-O file.  */
737
 
738
static const char *
739
simple_object_mach_o_find_sections (simple_object_read *sobj,
740
				    int (*pfn) (void *, const char *,
741
						off_t offset, off_t length),
742
				    void *data,
743
				    int *err)
744
{
745
  struct simple_object_mach_o_read *omr =
746
    (struct simple_object_mach_o_read *) sobj->data;
747
  off_t offset;
748
  size_t seghdrsize;
749
  unsigned int (*fetch_32) (const unsigned char *);
750
  const char *errmsg;
751
  unsigned int i;
752
 
753
  if (omr->magic == MACH_O_MH_MAGIC)
754
    {
755
      offset = sizeof (struct mach_o_header_32);
756
      seghdrsize = sizeof (struct mach_o_segment_command_32);
757
    }
758
  else
759
    {
760
      offset = sizeof (struct mach_o_header_64);
761
      seghdrsize = sizeof (struct mach_o_segment_command_64);
762
    }
763
 
764
  fetch_32 = (omr->is_big_endian
765
	      ? simple_object_fetch_big_32
766
	      : simple_object_fetch_little_32);
767
 
768
  for (i = 0; i < omr->ncmds; ++i)
769
    {
770
      unsigned char loadbuf[sizeof (struct mach_o_load_command)];
771
      unsigned int cmd;
772
      unsigned int cmdsize;
773
 
774
      if (!simple_object_internal_read (sobj->descriptor,
775
					sobj->offset + offset,
776
					loadbuf,
777
					sizeof (struct mach_o_load_command),
778
					&errmsg, err))
779
	return errmsg;
780
 
781
      cmd = (*fetch_32) (loadbuf + offsetof (struct mach_o_load_command, cmd));
782
      cmdsize = (*fetch_32) (loadbuf
783
			     + offsetof (struct mach_o_load_command, cmdsize));
784
 
785
      if (cmd == MACH_O_LC_SEGMENT || cmd == MACH_O_LC_SEGMENT_64)
786
	{
787
	  unsigned char segbuf[sizeof (struct mach_o_segment_command_64)];
788
	  int r;
789
 
790
	  if (!simple_object_internal_read (sobj->descriptor,
791
					    sobj->offset + offset,
792
					    segbuf, seghdrsize, &errmsg, err))
793
	    return errmsg;
794
 
795
	  r = simple_object_mach_o_segment (sobj, offset, segbuf, pfn,
796
					    data, &errmsg, err);
797
	  if (!r)
798
	    return errmsg;
799
	}
800
 
801
      offset += cmdsize;
802
    }
803
 
804
  return NULL;
805
}
806
 
807
/* Fetch the attributes for an simple_object_read.  */
808
 
809
static void *
810
simple_object_mach_o_fetch_attributes (simple_object_read *sobj,
811
				       const char **errmsg ATTRIBUTE_UNUSED,
812
				       int *err ATTRIBUTE_UNUSED)
813
{
814
  struct simple_object_mach_o_read *omr =
815
    (struct simple_object_mach_o_read *) sobj->data;
816
  struct simple_object_mach_o_attributes *ret;
817
 
818
  ret = XNEW (struct simple_object_mach_o_attributes);
819
  ret->magic = omr->magic;
820
  ret->is_big_endian = omr->is_big_endian;
821
  ret->cputype = omr->cputype;
822
  ret->cpusubtype = omr->cpusubtype;
823
  ret->flags = omr->flags;
824
  ret->reserved = omr->reserved;
825
  return ret;
826
}
827
 
828
/* Release the private data for an simple_object_read.  */
829
 
830
static void
831
simple_object_mach_o_release_read (void *data)
832
{
833
  struct simple_object_mach_o_read *omr =
834
    (struct simple_object_mach_o_read *) data;
835
 
836
  free (omr->segment_name);
837
  XDELETE (omr);
838
}
839
 
840
/* Compare two attributes structures.  */
841
 
842
static const char *
843
simple_object_mach_o_attributes_merge (void *todata, void *fromdata, int *err)
844
{
845
  struct simple_object_mach_o_attributes *to =
846
    (struct simple_object_mach_o_attributes *) todata;
847
  struct simple_object_mach_o_attributes *from =
848
    (struct simple_object_mach_o_attributes *) fromdata;
849
 
850
  if (to->magic != from->magic
851
      || to->is_big_endian != from->is_big_endian
852
      || to->cputype != from->cputype)
853
    {
854
      *err = 0;
855
      return "Mach-O object format mismatch";
856
    }
857
  return NULL;
858
}
859
 
860
/* Release the private data for an attributes structure.  */
861
 
862
static void
863
simple_object_mach_o_release_attributes (void *data)
864
{
865
  XDELETE (data);
866
}
867
 
868
/* Prepare to write out a file.  */
869
 
870
static void *
871
simple_object_mach_o_start_write (void *attributes_data,
872
				  const char **errmsg ATTRIBUTE_UNUSED,
873
				  int *err ATTRIBUTE_UNUSED)
874
{
875
  struct simple_object_mach_o_attributes *attrs =
876
    (struct simple_object_mach_o_attributes *) attributes_data;
877
  struct simple_object_mach_o_attributes *ret;
878
 
879
  /* We're just going to record the attributes, but we need to make a
880
     copy because the user may delete them.  */
881
  ret = XNEW (struct simple_object_mach_o_attributes);
882
  *ret = *attrs;
883
  return ret;
884
}
885
 
886
/* Write out the header of a Mach-O file.  */
887
 
888
static int
889
simple_object_mach_o_write_header (simple_object_write *sobj, int descriptor,
890
				   size_t nsects, const char **errmsg,
891
				   int *err)
892
{
893
  struct simple_object_mach_o_attributes *attrs =
894
    (struct simple_object_mach_o_attributes *) sobj->data;
895
  void (*set_32) (unsigned char *, unsigned int);
896
  unsigned char hdrbuf[sizeof (struct mach_o_header_64)];
897
  unsigned char *hdr;
898
  size_t wrsize;
899
 
900
  set_32 = (attrs->is_big_endian
901
	    ? simple_object_set_big_32
902
	    : simple_object_set_little_32);
903
 
904
  memset (hdrbuf, 0, sizeof hdrbuf);
905
 
906
  /* The 32-bit and 64-bit headers start out the same.  */
907
 
908
  hdr = &hdrbuf[0];
909
  set_32 (hdr + offsetof (struct mach_o_header_32, magic), attrs->magic);
910
  set_32 (hdr + offsetof (struct mach_o_header_32, cputype), attrs->cputype);
911
  set_32 (hdr + offsetof (struct mach_o_header_32, cpusubtype),
912
	  attrs->cpusubtype);
913
  set_32 (hdr + offsetof (struct mach_o_header_32, filetype), MACH_O_MH_OBJECT);
914
  set_32 (hdr + offsetof (struct mach_o_header_32, ncmds), 1);
915
  set_32 (hdr + offsetof (struct mach_o_header_32, flags), attrs->flags);
916
  if (attrs->magic == MACH_O_MH_MAGIC)
917
    {
918
      wrsize = sizeof (struct mach_o_header_32);
919
      set_32 (hdr + offsetof (struct mach_o_header_32, sizeofcmds),
920
	      (sizeof (struct mach_o_segment_command_32)
921
	       + nsects * sizeof (struct mach_o_section_32)));
922
    }
923
  else
924
    {
925
      set_32 (hdr + offsetof (struct mach_o_header_64, sizeofcmds),
926
	      (sizeof (struct mach_o_segment_command_64)
927
	       + nsects * sizeof (struct mach_o_section_64)));
928
      set_32 (hdr + offsetof (struct mach_o_header_64, reserved),
929
	      attrs->reserved);
930
      wrsize = sizeof (struct mach_o_header_64);
931
    }
932
 
933
  return simple_object_internal_write (descriptor, 0, hdrbuf, wrsize,
934
				       errmsg, err);
935
}
936
 
937
/* Write a Mach-O section header.  */
938
 
939
static int
940
simple_object_mach_o_write_section_header (simple_object_write *sobj,
941
					   int descriptor,
942
					   size_t sechdr_offset,
943
					   const char *name, const char *segn,
944
					   size_t secaddr, size_t secsize,
945
					   size_t offset, unsigned int align,
946
					   const char **errmsg, int *err)
947
{
948
  struct simple_object_mach_o_attributes *attrs =
949
    (struct simple_object_mach_o_attributes *) sobj->data;
950
  void (*set_32) (unsigned char *, unsigned int);
951
  unsigned char hdrbuf[sizeof (struct mach_o_section_64)];
952
  unsigned char *hdr;
953
  size_t sechdrsize;
954
 
955
  set_32 = (attrs->is_big_endian
956
	    ? simple_object_set_big_32
957
	    : simple_object_set_little_32);
958
 
959
  memset (hdrbuf, 0, sizeof hdrbuf);
960
 
961
  hdr = &hdrbuf[0];
962
  if (attrs->magic == MACH_O_MH_MAGIC)
963
    {
964
      strncpy ((char *) hdr + offsetof (struct mach_o_section_32, sectname),
965
	       name, MACH_O_NAME_LEN);
966
      strncpy ((char *) hdr + offsetof (struct mach_o_section_32, segname),
967
	       segn, MACH_O_NAME_LEN);
968
      set_32 (hdr + offsetof (struct mach_o_section_32, addr), secaddr);
969
      set_32 (hdr + offsetof (struct mach_o_section_32, size), secsize);
970
      set_32 (hdr + offsetof (struct mach_o_section_32, offset), offset);
971
      set_32 (hdr + offsetof (struct mach_o_section_32, align), align);
972
      /* reloff left as zero.  */
973
      /* nreloc left as zero.  */
974
      set_32 (hdr + offsetof (struct mach_o_section_32, flags),
975
	      MACH_O_S_ATTR_DEBUG);
976
      /* reserved1 left as zero.  */
977
      /* reserved2 left as zero.  */
978
      sechdrsize = sizeof (struct mach_o_section_32);
979
    }
980
  else
981
    {
982
#ifdef UNSIGNED_64BIT_TYPE
983
      void (*set_64) (unsigned char *, ulong_type);
984
 
985
      set_64 = (attrs->is_big_endian
986
		? simple_object_set_big_64
987
		: simple_object_set_little_64);
988
 
989
      strncpy ((char *) hdr + offsetof (struct mach_o_section_64, sectname),
990
	       name, MACH_O_NAME_LEN);
991
      strncpy ((char *) hdr + offsetof (struct mach_o_section_64, segname),
992
	       segn, MACH_O_NAME_LEN);
993
      set_64 (hdr + offsetof (struct mach_o_section_64, addr), secaddr);
994
      set_64 (hdr + offsetof (struct mach_o_section_64, size), secsize);
995
      set_32 (hdr + offsetof (struct mach_o_section_64, offset), offset);
996
      set_32 (hdr + offsetof (struct mach_o_section_64, align), align);
997
      /* reloff left as zero.  */
998
      /* nreloc left as zero.  */
999
      set_32 (hdr + offsetof (struct mach_o_section_64, flags),
1000
	      MACH_O_S_ATTR_DEBUG);
1001
      /* reserved1 left as zero.  */
1002
      /* reserved2 left as zero.  */
1003
      /* reserved3 left as zero.  */
1004
#endif
1005
      sechdrsize = sizeof (struct mach_o_section_64);
1006
    }
1007
 
1008
  return simple_object_internal_write (descriptor, sechdr_offset, hdr,
1009
				       sechdrsize, errmsg, err);
1010
}
1011
 
1012
/* Write out the single (anonymous) segment containing the sections of a Mach-O
1013
   Object file.
1014
 
1015
   As a GNU extension to mach-o, when the caller specifies a segment name in
1016
   sobj->segment_name, all the sections passed will be output under a single
1017
   mach-o section header.  The caller's sections are indexed within this
1018
   'wrapper' section by a table stored in a second mach-o section.  Finally,
1019
   arbitrary length section names are permitted by the extension and these are
1020
   stored in a table in a third mach-o section.
1021
 
1022
   Note that this is only likely to make any sense for the __GNU_LTO segment
1023
   at present.
1024
 
1025
   If the wrapper extension is not in force, we assume that the section name
1026
   is in the form __SEGMENT_NAME,__section_name as per Mach-O asm.  */
1027
 
1028
static int
1029
simple_object_mach_o_write_segment (simple_object_write *sobj, int descriptor,
1030
				    size_t *nsects, const char **errmsg,
1031
				    int *err)
1032
{
1033
  struct simple_object_mach_o_attributes *attrs =
1034
    (struct simple_object_mach_o_attributes *) sobj->data;
1035
  void (*set_32) (unsigned char *, unsigned int);
1036
  size_t hdrsize;
1037
  size_t seghdrsize;
1038
  size_t sechdrsize;
1039
  size_t cmdsize;
1040
  size_t offset;
1041
  size_t sechdr_offset;
1042
  size_t secaddr;
1043
  unsigned int name_offset;
1044
  simple_object_write_section *section;
1045
  unsigned char hdrbuf[sizeof (struct mach_o_segment_command_64)];
1046
  unsigned char *hdr;
1047
  size_t nsects_in;
1048
  unsigned int *index;
1049
  char *snames;
1050
  unsigned int sect;
1051
 
1052
  set_32 = (attrs->is_big_endian
1053
	    ? simple_object_set_big_32
1054
	    : simple_object_set_little_32);
1055
 
1056
  /* Write out the sections first.  */
1057
 
1058
  if (attrs->magic == MACH_O_MH_MAGIC)
1059
    {
1060
      hdrsize = sizeof (struct mach_o_header_32);
1061
      seghdrsize = sizeof (struct mach_o_segment_command_32);
1062
      sechdrsize = sizeof (struct mach_o_section_32);
1063
    }
1064
  else
1065
    {
1066
      hdrsize = sizeof (struct mach_o_header_64);
1067
      seghdrsize = sizeof (struct mach_o_segment_command_64);
1068
      sechdrsize = sizeof (struct mach_o_section_64);
1069
    }
1070
 
1071
  name_offset = 0;
1072
  *nsects = nsects_in = 0;
1073
 
1074
  /* Count the number of sections we start with.  */
1075
 
1076
  for (section = sobj->sections; section != NULL; section = section->next)
1077
    nsects_in++;
1078
 
1079
  if (sobj->segment_name != NULL)
1080
    {
1081
      /* We will only write 3 sections: wrapped data, index and names.  */
1082
 
1083
      *nsects = 3;
1084
 
1085
      /* The index has four entries per wrapped section:
1086
	   Section Offset, length,  Name offset, length.
1087
	 Where the offsets are based at the start of the wrapper and name
1088
	 sections respectively.
1089
	 The values are stored as 32 bit int for both 32 and 64 bit mach-o
1090
	 since the size of a mach-o MH_OBJECT cannot exceed 4G owing to
1091
	 other constraints.  */
1092
 
1093
      index = XNEWVEC (unsigned int, nsects_in * 4);
1094
 
1095
      /* We now need to figure out the size of the names section.  This just
1096
	 stores the names as null-terminated c strings, packed without any
1097
	 alignment padding.  */
1098
 
1099
      for (section = sobj->sections, sect = 0; section != NULL;
1100
	   section = section->next, sect++)
1101
	{
1102
	  index[sect*4+2] = name_offset;
1103
	  index[sect*4+3] = strlen (section->name) + 1;
1104
	  name_offset += strlen (section->name) + 1;
1105
	}
1106
      snames = XNEWVEC (char, name_offset);
1107
    }
1108
  else
1109
    {
1110
      *nsects = nsects_in;
1111
      index = NULL;
1112
      snames = NULL;
1113
    }
1114
 
1115
  sechdr_offset = hdrsize + seghdrsize;
1116
  cmdsize = seghdrsize + *nsects * sechdrsize;
1117
  offset = hdrsize + cmdsize;
1118
  secaddr = 0;
1119
 
1120
  for (section = sobj->sections, sect = 0;
1121
       section != NULL; section = section->next, sect++)
1122
    {
1123
      size_t mask;
1124
      size_t new_offset;
1125
      size_t secsize;
1126
      struct simple_object_write_section_buffer *buffer;
1127
 
1128
      mask = (1U << section->align) - 1;
1129
      new_offset = offset + mask;
1130
      new_offset &= ~ mask;
1131
      while (new_offset > offset)
1132
	{
1133
	  unsigned char zeroes[16];
1134
	  size_t write;
1135
 
1136
	  memset (zeroes, 0, sizeof zeroes);
1137
	  write = new_offset - offset;
1138
	  if (write > sizeof zeroes)
1139
	    write = sizeof zeroes;
1140
	  if (!simple_object_internal_write (descriptor, offset, zeroes, write,
1141
					     errmsg, err))
1142
	    return 0;
1143
	  offset += write;
1144
	}
1145
 
1146
      secsize = 0;
1147
      for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
1148
	{
1149
	  if (!simple_object_internal_write (descriptor, offset + secsize,
1150
					     ((const unsigned char *)
1151
					      buffer->buffer),
1152
					     buffer->size, errmsg, err))
1153
	    return 0;
1154
	  secsize += buffer->size;
1155
	}
1156
 
1157
      if (sobj->segment_name != NULL)
1158
	{
1159
	  index[sect*4+0] = (unsigned int) offset;
1160
	  index[sect*4+1] = secsize;
1161
	  /* Stash the section name in our table.  */
1162
	  memcpy (snames + index[sect * 4 + 2], section->name,
1163
		  index[sect * 4 + 3]);
1164
	}
1165
      else
1166
	{
1167
	  char namebuf[MACH_O_NAME_LEN + 1];
1168
	  char segnbuf[MACH_O_NAME_LEN + 1];
1169
	  char *comma;
1170
 
1171
	  /* Try to extract segment,section from the input name.  */
1172
 
1173
	  memset (namebuf, 0, sizeof namebuf);
1174
	  memset (segnbuf, 0, sizeof segnbuf);
1175
	  comma = strchr (section->name, ',');
1176
	  if (comma != NULL)
1177
	    {
1178
	      int len = comma - section->name;
1179
	      len = len > MACH_O_NAME_LEN ? MACH_O_NAME_LEN : len;
1180
	      strncpy (namebuf, section->name, len);
1181
	      strncpy (segnbuf, comma + 1, MACH_O_NAME_LEN);
1182
	    }
1183
	  else /* just try to copy the name, leave segment blank.  */
1184
	    strncpy (namebuf, section->name, MACH_O_NAME_LEN);
1185
 
1186
	  if (!simple_object_mach_o_write_section_header (sobj, descriptor,
1187
							  sechdr_offset,
1188
							  namebuf, segnbuf,
1189
							  secaddr, secsize,
1190
							  offset,
1191
							  section->align,
1192
							  errmsg, err))
1193
	    return 0;
1194
	  sechdr_offset += sechdrsize;
1195
	}
1196
 
1197
      offset += secsize;
1198
      secaddr += secsize;
1199
    }
1200
 
1201
  if (sobj->segment_name != NULL)
1202
    {
1203
      size_t secsize;
1204
      unsigned int i;
1205
 
1206
      /* Write the section header for the wrapper.  */
1207
      /* Account for any initial aligment - which becomes the alignment for this
1208
	 created section.  */
1209
 
1210
      secsize = (offset - index[0]);
1211
      if (!simple_object_mach_o_write_section_header (sobj, descriptor,
1212
						      sechdr_offset,
1213
						      GNU_WRAPPER_SECTS,
1214
						      sobj->segment_name,
1215
 
1216
						      secsize, index[0],
1217
						      sobj->sections->align,
1218
						      errmsg, err))
1219
	return 0;
1220
 
1221
      /* Subtract the wrapper section start from the begining of each sub
1222
	 section.  */
1223
 
1224
      for (i = 1; i < nsects_in; ++i)
1225
	index[4 * i] -= index[0];
1226
      index[0] = 0;
1227
 
1228
      sechdr_offset += sechdrsize;
1229
 
1230
      /* Write out the section names.
1231
	 ... the header ...
1232
	 name_offset contains the length of the section.  It is not aligned.  */
1233
 
1234
      if (!simple_object_mach_o_write_section_header (sobj, descriptor,
1235
						      sechdr_offset,
1236
						      GNU_WRAPPER_NAMES,
1237
						      sobj->segment_name,
1238
 
1239
						      name_offset,
1240
						      offset,
1241
						      0, errmsg, err))
1242
	return 0;
1243
 
1244
      /* ... and the content.. */
1245
      if (!simple_object_internal_write (descriptor, offset,
1246
					 (const unsigned char *) snames,
1247
					 name_offset, errmsg, err))
1248
	return 0;
1249
 
1250
      sechdr_offset += sechdrsize;
1251
      secaddr += name_offset;
1252
      offset += name_offset;
1253
 
1254
      /* Now do the index, we'll align this to 4 bytes although the read code
1255
	 will handle unaligned.  */
1256
 
1257
      offset += 3;
1258
      offset &= ~0x03;
1259
      if (!simple_object_mach_o_write_section_header (sobj, descriptor,
1260
						      sechdr_offset,
1261
						      GNU_WRAPPER_INDEX,
1262
						      sobj->segment_name,
1263
 
1264
						      nsects_in * 16,
1265
						      offset,
1266
						      2, errmsg, err))
1267
	return 0;
1268
 
1269
      /* ... and the content.. */
1270
      if (!simple_object_internal_write (descriptor, offset,
1271
					 (const unsigned char *) index,
1272
					 nsects_in*16, errmsg, err))
1273
	return 0;
1274
 
1275
      XDELETEVEC (index);
1276
      XDELETEVEC (snames);
1277
    }
1278
 
1279
  /* Write out the segment header.  */
1280
 
1281
  memset (hdrbuf, 0, sizeof hdrbuf);
1282
 
1283
  hdr = &hdrbuf[0];
1284
  if (attrs->magic == MACH_O_MH_MAGIC)
1285
    {
1286
      set_32 (hdr + offsetof (struct mach_o_segment_command_32, cmd),
1287
	      MACH_O_LC_SEGMENT);
1288
      set_32 (hdr + offsetof (struct mach_o_segment_command_32, cmdsize),
1289
	      cmdsize);
1290
     /* MH_OBJECTS have a single, anonymous, segment - so the segment name
1291
	 is left empty.  */
1292
      /* vmaddr left as zero.  */
1293
      /* vmsize left as zero.  */
1294
      set_32 (hdr + offsetof (struct mach_o_segment_command_32, fileoff),
1295
	      hdrsize + cmdsize);
1296
      set_32 (hdr + offsetof (struct mach_o_segment_command_32, filesize),
1297
	      offset - (hdrsize + cmdsize));
1298
      /* maxprot left as zero.  */
1299
      /* initprot left as zero.  */
1300
      set_32 (hdr + offsetof (struct mach_o_segment_command_32, nsects),
1301
	      *nsects);
1302
      /* flags left as zero.  */
1303
    }
1304
  else
1305
    {
1306
#ifdef UNSIGNED_64BIT_TYPE
1307
      void (*set_64) (unsigned char *, ulong_type);
1308
 
1309
      set_64 = (attrs->is_big_endian
1310
		? simple_object_set_big_64
1311
		: simple_object_set_little_64);
1312
 
1313
      set_32 (hdr + offsetof (struct mach_o_segment_command_64, cmd),
1314
	      MACH_O_LC_SEGMENT);
1315
      set_32 (hdr + offsetof (struct mach_o_segment_command_64, cmdsize),
1316
	      cmdsize);
1317
      /* MH_OBJECTS have a single, anonymous, segment - so the segment name
1318
	 is left empty.  */
1319
      /* vmaddr left as zero.  */
1320
      /* vmsize left as zero.  */
1321
      set_64 (hdr + offsetof (struct mach_o_segment_command_64, fileoff),
1322
	      hdrsize + cmdsize);
1323
      set_64 (hdr + offsetof (struct mach_o_segment_command_64, filesize),
1324
	      offset - (hdrsize + cmdsize));
1325
      /* maxprot left as zero.  */
1326
      /* initprot left as zero.  */
1327
      set_32 (hdr + offsetof (struct mach_o_segment_command_64, nsects),
1328
	      *nsects);
1329
      /* flags left as zero.  */
1330
#endif
1331
    }
1332
 
1333
  return simple_object_internal_write (descriptor, hdrsize, hdr, seghdrsize,
1334
				       errmsg, err);
1335
}
1336
 
1337
/* Write out a complete Mach-O file.  */
1338
 
1339
static const char *
1340
simple_object_mach_o_write_to_file (simple_object_write *sobj, int descriptor,
1341
				    int *err)
1342
{
1343
  size_t nsects = 0;
1344
  const char *errmsg;
1345
 
1346
  if (!simple_object_mach_o_write_segment (sobj, descriptor, &nsects,
1347
					   &errmsg, err))
1348
    return errmsg;
1349
 
1350
  if (!simple_object_mach_o_write_header (sobj, descriptor, nsects,
1351
					  &errmsg, err))
1352
    return errmsg;
1353
 
1354
  return NULL;
1355
}
1356
 
1357
/* Release the private data for an simple_object_write structure.  */
1358
 
1359
static void
1360
simple_object_mach_o_release_write (void *data)
1361
{
1362
  XDELETE (data);
1363
}
1364
 
1365
/* The Mach-O functions.  */
1366
 
1367
const struct simple_object_functions simple_object_mach_o_functions =
1368
{
1369
  simple_object_mach_o_match,
1370
  simple_object_mach_o_find_sections,
1371
  simple_object_mach_o_fetch_attributes,
1372
  simple_object_mach_o_release_read,
1373
  simple_object_mach_o_attributes_merge,
1374
  simple_object_mach_o_release_attributes,
1375
  simple_object_mach_o_start_write,
1376
  simple_object_mach_o_write_to_file,
1377
  simple_object_mach_o_release_write
1378
};