OpenCores
URL https://opencores.org/ocsvn/open8_urisc/open8_urisc/trunk

Subversion Repositories open8_urisc

[/] [open8_urisc/] [trunk/] [gnu/] [binutils/] [libiberty/] [simple-object-mach-o.c] - Blame information for rev 21

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 21 khays
/* 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.
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 <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
 
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
/* Private data for an simple_object_read.  */
178
 
179
struct simple_object_mach_o_read
180
{
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;
197
};
198
 
199
/* Private data for an simple_object_attributes.  */
200
 
201
struct simple_object_mach_o_attributes
202
{
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;
215
};
216
 
217
/* See if we have a Mach-O file.  */
218
 
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)
227
{
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;
235
 
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
240
    {
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
245
        {
246
          *errmsg = NULL;
247
          *err = 0;
248
          return NULL;
249
        }
250
    }
251
 
252
#ifndef UNSIGNED_64BIT_TYPE
253
  if (magic == MACH_O_MH_MAGIC_64)
254
    {
255
      *errmsg = "64-bit Mach-O objects not supported";
256
      *err = 0;
257
      return NULL;
258
    }
259
#endif
260
 
261
  /* We require the user to provide a segment name.  This is
262
     unfortunate but I don't see any good choices here.  */
263
 
264
  if (segment_name == NULL)
265
    {
266
      *errmsg = "Mach-O file found but no segment name specified";
267
      *err = 0;
268
      return NULL;
269
    }
270
 
271
  if (strlen (segment_name) > MACH_O_NAME_LEN)
272
    {
273
      *errmsg = "Mach-O segment name too long";
274
      *err = 0;
275
      return NULL;
276
    }
277
 
278
  /* The 32-bit and 64-bit headers are similar enough that we can use
279
     the same code.  */
280
 
281
  fetch_32 = (is_big_endian
282
              ? simple_object_fetch_big_32
283
              : simple_object_fetch_little_32);
284
 
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;
291
 
292
  b = &buf[0];
293
 
294
  filetype = (*fetch_32) (b + offsetof (struct mach_o_header_32, filetype));
295
  if (filetype != MACH_O_MH_OBJECT)
296
    {
297
      *errmsg = "Mach-O file is not object file";
298
      *err = 0;
299
      return NULL;
300
    }
301
 
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));
318
 
319
  return (void *) omr;
320
}
321
 
322
/* Get the file offset and size from a section header.  */
323
 
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)
328
{
329
  unsigned int (*fetch_32) (const unsigned char *);
330
  ulong_type (*fetch_64) (const unsigned char *);
331
 
332
  fetch_32 = (is_big_endian
333
              ? simple_object_fetch_big_32
334
              : simple_object_fetch_little_32);
335
 
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
342
 
343
  if (is_32)
344
    {
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));
349
    }
350
  else
351
    {
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));
356
    }
357
}
358
 
359
/* Handle a segment in a Mach-O file.  Return 1 if we should continue,
360
 
361
 
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)
369
{
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;
384
 
385
  fetch_32 = (omr->is_big_endian
386
              ? simple_object_fetch_big_32
387
              : simple_object_fetch_little_32);
388
 
389
  is_32 = omr->magic == MACH_O_MH_MAGIC;
390
 
391
  if (is_32)
392
    {
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));
400
    }
401
  else
402
    {
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));
410
    }
411
 
412
  secdata = XNEWVEC (unsigned char, nsects * sechdrsize);
413
  if (!simple_object_internal_read (sobj->descriptor, offset + seghdrsize,
414
                                    secdata, nsects * sechdrsize, errmsg, err))
415
    {
416
      XDELETEVEC (secdata);
417
      return 0;
418
    }
419
 
420
  /* Scan for a __section_names section.  This is in effect a GNU
421
     extension that permits section names longer than 16 chars.  */
422
 
423
  for (i = 0; i < nsects; ++i)
424
    {
425
      size_t nameoff;
426
 
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;
433
    }
434
 
435
  strtab_index = i;
436
  if (strtab_index >= nsects)
437
    {
438
      strtab = NULL;
439
      strtab_size = 0;
440
    }
441
  else
442
    {
443
      off_t strtab_offset;
444
 
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))
453
        {
454
          XDELETEVEC (strtab);
455
          XDELETEVEC (secdata);
456
          return 0;
457
        }
458
    }
459
 
460
  /* Process the sections.  */
461
 
462
  for (i = 0; i < nsects; ++i)
463
    {
464
      const unsigned char *sechdr;
465
      char namebuf[MACH_O_NAME_LEN + 1];
466
      char *name;
467
      off_t secoffset;
468
      size_t secsize;
469
 
470
      if (i == strtab_index)
471
        continue;
472
 
473
      sechdr = secdata + i * sechdrsize;
474
 
475
      if (strcmp ((char *) sechdr + segname_offset, omr->segment_name) != 0)
476
        continue;
477
 
478
      memcpy (namebuf, sechdr + sectname_offset, MACH_O_NAME_LEN);
479
      namebuf[MACH_O_NAME_LEN] = '\0';
480
 
481
      name = &namebuf[0];
482
      if (strtab != NULL && name[0] == '_' && name[1] == '_')
483
        {
484
          unsigned long stringoffset;
485
 
486
          if (sscanf (name + 2, "%08lX", &stringoffset) == 1)
487
            {
488
              if (stringoffset >= strtab_size)
489
                {
490
                  *errmsg = "section name offset out of range";
491
                  *err = 0;
492
                  XDELETEVEC (strtab);
493
                  XDELETEVEC (secdata);
494
                  return 0;
495
                }
496
 
497
              name = strtab + stringoffset;
498
            }
499
        }
500
 
501
      simple_object_mach_o_section_info (omr->is_big_endian, is_32, sechdr,
502
                                         &secoffset, &secsize);
503
 
504
      if (!(*pfn) (data, name, secoffset, secsize))
505
        {
506
          *errmsg = NULL;
507
          *err = 0;
508
          XDELETEVEC (strtab);
509
          XDELETEVEC (secdata);
510
          return 0;
511
        }
512
    }
513
 
514
  XDELETEVEC (strtab);
515
  XDELETEVEC (secdata);
516
 
517
  return 1;
518
}
519
 
520
/* Find all sections in a Mach-O file.  */
521
 
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)
528
{
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;
536
 
537
  if (omr->magic == MACH_O_MH_MAGIC)
538
    {
539
      offset = sizeof (struct mach_o_header_32);
540
      seghdrsize = sizeof (struct mach_o_segment_command_32);
541
    }
542
  else
543
    {
544
      offset = sizeof (struct mach_o_header_64);
545
      seghdrsize = sizeof (struct mach_o_segment_command_64);
546
    }
547
 
548
  fetch_32 = (omr->is_big_endian
549
              ? simple_object_fetch_big_32
550
              : simple_object_fetch_little_32);
551
 
552
  for (i = 0; i < omr->ncmds; ++i)
553
    {
554
      unsigned char loadbuf[sizeof (struct mach_o_load_command)];
555
      unsigned int cmd;
556
      unsigned int cmdsize;
557
 
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;
564
 
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));
568
 
569
      if (cmd == MACH_O_LC_SEGMENT || cmd == MACH_O_LC_SEGMENT_64)
570
        {
571
          unsigned char segbuf[sizeof (struct mach_o_segment_command_64)];
572
          int r;
573
 
574
          if (!simple_object_internal_read (sobj->descriptor,
575
                                            sobj->offset + offset,
576
                                            segbuf, seghdrsize, &errmsg, err))
577
            return errmsg;
578
 
579
          r = simple_object_mach_o_segment (sobj, offset, segbuf, pfn,
580
                                            data, &errmsg, err);
581
          if (!r)
582
            return errmsg;
583
        }
584
 
585
      offset += cmdsize;
586
    }
587
 
588
  return NULL;
589
}
590
 
591
/* Fetch the attributes for an simple_object_read.  */
592
 
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)
597
{
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;
601
 
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;
610
}
611
 
612
/* Release the private data for an simple_object_read.  */
613
 
614
static void
615
simple_object_mach_o_release_read (void *data)
616
{
617
  struct simple_object_mach_o_read *omr =
618
    (struct simple_object_mach_o_read *) data;
619
 
620
  free (omr->segment_name);
621
  XDELETE (omr);
622
}
623
 
624
/* Compare two attributes structures.  */
625
 
626
static const char *
627
simple_object_mach_o_attributes_merge (void *todata, void *fromdata, int *err)
628
{
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;
633
 
634
  if (to->magic != from->magic
635
      || to->is_big_endian != from->is_big_endian
636
      || to->cputype != from->cputype)
637
    {
638
      *err = 0;
639
      return "Mach-O object format mismatch";
640
    }
641
  return NULL;
642
}
643
 
644
/* Release the private data for an attributes structure.  */
645
 
646
static void
647
simple_object_mach_o_release_attributes (void *data)
648
{
649
  XDELETE (data);
650
}
651
 
652
/* Prepare to write out a file.  */
653
 
654
static void *
655
simple_object_mach_o_start_write (void *attributes_data,
656
                                  const char **errmsg ATTRIBUTE_UNUSED,
657
                                  int *err ATTRIBUTE_UNUSED)
658
{
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;
662
 
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;
668
}
669
 
670
/* Write out the header of a Mach-O file.  */
671
 
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)
676
{
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;
683
 
684
  set_32 = (attrs->is_big_endian
685
            ? simple_object_set_big_32
686
            : simple_object_set_little_32);
687
 
688
  memset (hdrbuf, 0, sizeof hdrbuf);
689
 
690
  /* The 32-bit and 64-bit headers start out the same.  */
691
 
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)
701
    {
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)));
706
    }
707
  else
708
    {
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);
715
    }
716
 
717
  return simple_object_internal_write (descriptor, 0, hdrbuf, wrsize,
718
                                       errmsg, err);
719
}
720
 
721
/* Write a Mach-O section header.  */
722
 
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)
731
{
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;
738
 
739
  set_32 = (attrs->is_big_endian
740
            ? simple_object_set_big_32
741
            : simple_object_set_little_32);
742
 
743
  memset (hdrbuf, 0, sizeof hdrbuf);
744
 
745
  hdr = &hdrbuf[0];
746
  if (attrs->magic == MACH_O_MH_MAGIC)
747
    {
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);
763
    }
764
  else
765
    {
766
#ifdef UNSIGNED_64BIT_TYPE
767
      void (*set_64) (unsigned char *, ulong_type);
768
 
769
      set_64 = (attrs->is_big_endian
770
                ? simple_object_set_big_64
771
                : simple_object_set_little_64);
772
 
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);
790
    }
791
 
792
  return simple_object_internal_write (descriptor, sechdr_offset, hdr,
793
                                       sechdrsize, errmsg, err);
794
}
795
 
796
/* Write out the single segment and the sections of a Mach-O file.  */
797
 
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)
802
{
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;
817
 
818
  set_32 = (attrs->is_big_endian
819
            ? simple_object_set_big_32
820
            : simple_object_set_little_32);
821
 
822
  /* Write out the sections first.  */
823
 
824
  if (attrs->magic == MACH_O_MH_MAGIC)
825
    {
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);
829
    }
830
  else
831
    {
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);
835
    }
836
 
837
  sechdr_offset = hdrsize + seghdrsize;
838
  cmdsize = seghdrsize + nsects * sechdrsize;
839
  offset = hdrsize + cmdsize;
840
  name_offset = 0;
841
  secaddr = 0;
842
 
843
  for (section = sobj->sections; section != NULL; section = section->next)
844
    {
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];
850
 
851
      mask = (1U << section->align) - 1;
852
      new_offset = offset + mask;
853
      new_offset &= ~ mask;
854
      while (new_offset > offset)
855
        {
856
          unsigned char zeroes[16];
857
          size_t write;
858
 
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;
867
        }
868
 
869
      secsize = 0;
870
      for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
871
        {
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;
878
        }
879
 
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;
887
 
888
      sechdr_offset += sechdrsize;
889
      offset += secsize;
890
      name_offset += strlen (section->name) + 1;
891
      secaddr += secsize;
892
    }
893
 
894
  /* Write out the section names.  */
895
 
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;
902
 
903
  for (section = sobj->sections; section != NULL; section = section->next)
904
    {
905
      size_t namelen;
906
 
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;
913
    }
914
 
915
  /* Write out the segment header.  */
916
 
917
  memset (hdrbuf, 0, sizeof hdrbuf);
918
 
919
  hdr = &hdrbuf[0];
920
  if (attrs->magic == MACH_O_MH_MAGIC)
921
    {
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.  */
940
    }
941
  else
942
    {
943
#ifdef UNSIGNED_64BIT_TYPE
944
      void (*set_64) (unsigned char *, ulong_type);
945
 
946
      set_64 = (attrs->is_big_endian
947
                ? simple_object_set_big_64
948
                : simple_object_set_little_64);
949
 
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
969
    }
970
 
971
  return simple_object_internal_write (descriptor, hdrsize, hdr, seghdrsize,
972
                                       errmsg, err);
973
}
974
 
975
/* Write out a complete Mach-O file.  */
976
 
977
static const char *
978
simple_object_mach_o_write_to_file (simple_object_write *sobj, int descriptor,
979
                                    int *err)
980
{
981
  size_t nsects;
982
  simple_object_write_section *section;
983
  const char *errmsg;
984
 
985
  /* Start at 1 for symbol_names section.  */
986
  nsects = 1;
987
  for (section = sobj->sections; section != NULL; section = section->next)
988
    ++nsects;
989
 
990
  if (!simple_object_mach_o_write_header (sobj, descriptor, nsects,
991
                                          &errmsg, err))
992
    return errmsg;
993
 
994
  if (!simple_object_mach_o_write_segment (sobj, descriptor, nsects,
995
                                           &errmsg, err))
996
    return errmsg;
997
 
998
  return NULL;
999
}
1000
 
1001
/* Release the private data for an simple_object_write structure.  */
1002
 
1003
static void
1004
simple_object_mach_o_release_write (void *data)
1005
{
1006
  XDELETE (data);
1007
}
1008
 
1009
/* The Mach-O functions.  */
1010
 
1011
const struct simple_object_functions simple_object_mach_o_functions =
1012
{
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
1022
};

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.