Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5191 serge 1
/* simple-object-coff.c -- routines to manipulate XCOFF object files.
2
   Copyright 2013 Free Software Foundation, Inc.
3
   Written by Ian Lance Taylor, Google and David Edelsohn, IBM.
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
#include 
26
 
27
#ifdef HAVE_STDLIB_H
28
#include 
29
#endif
30
 
31
#ifdef HAVE_STDINT_H
32
#include 
33
#endif
34
 
35
#ifdef HAVE_STRING_H
36
#include 
37
#endif
38
 
39
#ifdef HAVE_INTTYPES_H
40
#include 
41
#endif
42
 
43
#include "simple-object-common.h"
44
 
45
/* XCOFF structures and constants.  */
46
 
47
/* XCOFF file header.  */
48
 
49
struct external_filehdr
50
{
51
  unsigned char f_magic[2];	/* magic number			*/
52
  unsigned char f_nscns[2];	/* number of sections		*/
53
  unsigned char f_timdat[4];	/* time & date stamp		*/
54
  union
55
  {
56
    struct
57
    {
58
      unsigned char f_symptr[4];	/* file pointer to symtab	*/
59
      unsigned char f_nsyms[4];	/* number of symtab entries	*/
60
      unsigned char f_opthdr[2];	/* sizeof(optional hdr)		*/
61
      unsigned char f_flags[2];	/* flags			*/
62
    } xcoff32;
63
    struct
64
    {
65
      unsigned char f_symptr[8];	/* file pointer to symtab	*/
66
      unsigned char f_opthdr[2];	/* sizeof(optional hdr)		*/
67
      unsigned char f_flags[2];	/* flags			*/
68
      unsigned char f_nsyms[4];	/* number of symtab entries	*/
69
    } xcoff64;
70
  } u;
71
};
72
 
73
/* Bits for filehdr f_flags field.  */
74
 
75
#define F_EXEC			(0x0002)
76
 
77
/* The known values of f_magic in an XCOFF file header.  */
78
 
79
#define U802WRMAGIC 0730        /* Writeable text segments.  */
80
#define U802ROMAGIC 0735        /* Readonly sharable text segments.  */
81
#define U802TOCMAGIC 0737       /* Readonly text segments and TOC.  */
82
#define U803XTOCMAGIC 0757      /* Aix 4.3 64-bit XCOFF.  */
83
#define U64_TOCMAGIC 0767       /* AIX 5+ 64-bit XCOFF.  */
84
 
85
/* XCOFF section header.  */
86
 
87
struct external_scnhdr
88
{
89
  unsigned char s_name[8];	/* section name				*/
90
  union
91
  {
92
    struct
93
    {
94
      unsigned char s_paddr[4];	/* physical address, aliased s_nlib 	*/
95
      unsigned char s_vaddr[4];	/* virtual address			*/
96
      unsigned char s_size[4];	/* section size				*/
97
      unsigned char s_scnptr[4];	/* file ptr to raw data for section */
98
      unsigned char s_relptr[4];	/* file ptr to relocation	*/
99
      unsigned char s_lnnoptr[4];	/* file ptr to line numbers	*/
100
      unsigned char s_nreloc[2];	/* number of relocation entries	*/
101
      unsigned char s_nlnno[2];	/* number of line number entries	*/
102
      unsigned char s_flags[4];	/* flags				*/
103
    } xcoff32;
104
    struct
105
    {
106
      unsigned char s_paddr[8];	/* physical address, aliased s_nlib 	*/
107
      unsigned char s_vaddr[8];	/* virtual address			*/
108
      unsigned char s_size[8];	/* section size				*/
109
      unsigned char s_scnptr[8];	/* file ptr to raw data for section */
110
      unsigned char s_relptr[8];	/* file ptr to relocation	*/
111
      unsigned char s_lnnoptr[8];	/* file ptr to line numbers	*/
112
      unsigned char s_nreloc[4];	/* number of relocation entries	*/
113
      unsigned char s_nlnno[4];	/* number of line number entries	*/
114
      unsigned char s_flags[4];	/* flags				*/
115
    } xcoff64;
116
  } u;
117
};
118
 
119
#define SCNHSZ32	(40)
120
#define SCNHSZ64	(68)
121
 
122
/* The length of the s_name field in struct external_scnhdr.  */
123
 
124
#define SCNNMLEN	(8)
125
 
126
/* Bits for scnhdr s_flags field.  */
127
 
128
#define STYP_DATA			0x40
129
 
130
/* XCOFF symbol table entry.  */
131
 
132
 
133
#define N_SYMNMLEN	(8)	/* # characters in a symbol name	*/
134
 
135
/* The format of an XCOFF symbol-table entry.  */
136
struct external_syment
137
{
138
  union {
139
    struct {
140
      union {
141
        /* The name of the symbol.  There is an implicit null character
142
           after the end of the array.  */
143
        char n_name[N_SYMNMLEN];
144
        struct {
145
          /* If n_zeroes is zero, n_offset is the offset the name from
146
             the start of the string table.  */
147
          unsigned char n_zeroes[4];
148
          unsigned char n_offset[4];
149
        } n;
150
      } n;
151
 
152
      /* The symbol's value.  */
153
      unsigned char n_value[4];
154
    } xcoff32;
155
    struct {
156
      /* The symbol's value.  */
157
      unsigned char n_value[8];
158
 
159
      /* The offset of the symbol from the start of the string table.  */
160
      unsigned char n_offset[4];
161
    } xcoff64;
162
  } u;
163
 
164
  /* The number of the section to which this symbol belongs.  */
165
  unsigned char n_scnum[2];
166
 
167
  /* The type of symbol.  (It can be interpreted as an n_lang
168
     and an n_cpu byte, but we don't care about that here.)  */
169
  unsigned char n_type[2];
170
 
171
  /* The class of symbol (a C_* value).  */
172
  unsigned char n_sclass[1];
173
 
174
  /* The number of auxiliary symbols attached to this entry.  */
175
  unsigned char n_numaux[1];
176
};
177
 
178
#define SYMESZ		(18)
179
 
180
/* Length allowed for filename in aux sym format 4.  */
181
 
182
#define FILNMLEN	(14)
183
 
184
/* Omits x_sym and other unused variants.  */
185
 
186
union external_auxent
187
{
188
  /* Aux sym format 4: file.  */
189
  union
190
  {
191
    char x_fname[FILNMLEN];
192
    struct
193
    {
194
      unsigned char x_zeroes[4];
195
      unsigned char x_offset[4];
196
      unsigned char x_pad[FILNMLEN-8];
197
      unsigned char x_ftype;
198
    } _x;
199
  } x_file;
200
  /* Aux sym format 5: section.  */
201
  struct
202
  {
203
    unsigned char x_scnlen[4];		/* section length		*/
204
    unsigned char x_nreloc[2];		/* # relocation entries		*/
205
    unsigned char x_nlinno[2];		/* # line numbers		*/
206
  } x_scn;
207
  /* CSECT auxiliary entry.  */
208
  union
209
  {
210
    struct
211
    {
212
      struct
213
      {
214
	unsigned char x_scnlen[4];	/* csect length */
215
	unsigned char x_parmhash[4];	/* parm type hash index */
216
	unsigned char x_snhash[2];	/* sect num with parm hash */
217
	unsigned char x_smtyp;		/* symbol align and type */
218
	unsigned char x_smclas;		/* storage mapping class */
219
	unsigned char x_stab;		/* dbx stab info index */
220
	unsigned char x_snstab[2];	/* sect num with dbx stab */
221
      } x_csect;
222
    } xcoff32;
223
    struct
224
    {
225
      struct
226
      {
227
	unsigned char x_scnlen_lo[4];	/* csect length */
228
	unsigned char x_parmhash[4];	/* parm type hash index */
229
	unsigned char x_snhash[2];	/* sect num with parm hash */
230
	unsigned char x_smtyp;		/* symbol align and type */
231
	unsigned char x_smclas;		/* storage mapping class */
232
	unsigned char x_scnlen_hi[4];
233
	unsigned char pad;
234
	unsigned char x_auxtype;
235
      } x_csect;
236
    } xcoff64;
237
  } u;
238
  /* SECTION/DWARF auxiliary entry.  */
239
  struct
240
  {
241
    unsigned char x_scnlen[4];		/* section length */
242
    unsigned char pad1[4];
243
    unsigned char x_nreloc[4];		/* number RLDs */
244
  } x_sect;
245
};
246
 
247
/* Symbol-related constants.  */
248
 
249
#define N_DEBUG		(-2)
250
#define IMAGE_SYM_TYPE_NULL	(0)
251
#define IMAGE_SYM_DTYPE_NULL	(0)
252
#define IMAGE_SYM_CLASS_STATIC	(3)
253
#define IMAGE_SYM_CLASS_FILE	(103)
254
 
255
#define IMAGE_SYM_TYPE \
256
  ((IMAGE_SYM_DTYPE_NULL << 4) | IMAGE_SYM_TYPE_NULL)
257
 
258
#define C_STAT		(3)
259
#define C_FILE		(103)
260
 
261
/* Private data for an simple_object_read.  */
262
 
263
struct simple_object_xcoff_read
264
{
265
  /* Magic number.  */
266
  unsigned short magic;
267
  /* Number of sections.  */
268
  unsigned short nscns;
269
  /* File offset of symbol table.  */
270
  off_t symptr;
271
  /* Number of symbol table entries.  */
272
  unsigned int nsyms;
273
  /* Flags.  */
274
  unsigned short flags;
275
  /* Offset of section headers in file.  */
276
  off_t scnhdr_offset;
277
};
278
 
279
/* Private data for an simple_object_attributes.  */
280
 
281
struct simple_object_xcoff_attributes
282
{
283
  /* Magic number.  */
284
  unsigned short magic;
285
  /* Flags.  */
286
  unsigned short flags;
287
};
288
 
289
/* See if we have a XCOFF file.  */
290
 
291
static void *
292
simple_object_xcoff_match (unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN],
293
			   int descriptor, off_t offset,
294
			   const char *segment_name ATTRIBUTE_UNUSED,
295
			   const char **errmsg, int *err)
296
{
297
  unsigned short magic;
298
  unsigned short (*fetch_16) (const unsigned char *);
299
  unsigned int (*fetch_32) (const unsigned char *);
300
  ulong_type (*fetch_64) (const unsigned char *);
301
  unsigned char hdrbuf[sizeof (struct external_filehdr)];
302
  struct simple_object_xcoff_read *ocr;
303
  int u64;
304
 
305
  magic = simple_object_fetch_big_16 (header);
306
 
307
  if (magic != U802TOCMAGIC && magic != U64_TOCMAGIC)
308
    {
309
      *errmsg = NULL;
310
      *err = 0;
311
      return NULL;
312
    }
313
 
314
  fetch_16 = simple_object_fetch_big_16;
315
  fetch_32 = simple_object_fetch_big_32;
316
  fetch_64 = simple_object_fetch_big_64;
317
 
318
  if (!simple_object_internal_read (descriptor, offset, hdrbuf, sizeof hdrbuf,
319
				    errmsg, err))
320
    return NULL;
321
 
322
  u64 = magic == U64_TOCMAGIC;
323
 
324
  ocr = XNEW (struct simple_object_xcoff_read);
325
  ocr->magic = magic;
326
  ocr->nscns = fetch_16 (hdrbuf + offsetof (struct external_filehdr, f_nscns));
327
  if (u64)
328
    {
329
      ocr->symptr = fetch_64 (hdrbuf
330
			      + offsetof (struct external_filehdr,
331
					  u.xcoff64.f_symptr));
332
      ocr->nsyms = fetch_32 (hdrbuf + offsetof (struct external_filehdr,
333
						u.xcoff64.f_nsyms));
334
      ocr->scnhdr_offset = (sizeof (struct external_filehdr)
335
			    + fetch_16 (hdrbuf + offsetof (struct external_filehdr,
336
							   u.xcoff64.f_opthdr)));
337
 
338
    }
339
  else
340
    {
341
      ocr->symptr = fetch_32 (hdrbuf
342
			      + offsetof (struct external_filehdr,
343
					  u.xcoff32.f_symptr));
344
      ocr->nsyms = fetch_32 (hdrbuf + offsetof (struct external_filehdr,
345
						u.xcoff32.f_nsyms));
346
      ocr->scnhdr_offset = (sizeof (struct external_filehdr) - 4
347
			    + fetch_16 (hdrbuf + offsetof (struct external_filehdr,
348
							   u.xcoff32.f_opthdr)));
349
 
350
    }
351
 
352
  return (void *) ocr;
353
}
354
 
355
/* Read the string table in a XCOFF file.  */
356
 
357
static char *
358
simple_object_xcoff_read_strtab (simple_object_read *sobj, size_t *strtab_size,
359
				 const char **errmsg, int *err)
360
{
361
  struct simple_object_xcoff_read *ocr =
362
    (struct simple_object_xcoff_read *) sobj->data;
363
  off_t strtab_offset;
364
  unsigned char strsizebuf[4];
365
  size_t strsize;
366
  char *strtab;
367
 
368
  strtab_offset = sobj->offset + ocr->symptr
369
    + ocr->nsyms * SYMESZ;
370
  if (!simple_object_internal_read (sobj->descriptor, strtab_offset,
371
				    strsizebuf, 4, errmsg, err))
372
    return NULL;
373
  strsize = simple_object_fetch_big_32 (strsizebuf);
374
  strtab = XNEWVEC (char, strsize);
375
  if (!simple_object_internal_read (sobj->descriptor, strtab_offset,
376
				    (unsigned char *) strtab, strsize, errmsg,
377
				    err))
378
    {
379
      XDELETEVEC (strtab);
380
      return NULL;
381
    }
382
  *strtab_size = strsize;
383
  return strtab;
384
}
385
 
386
/* Find all sections in a XCOFF file.  */
387
 
388
static const char *
389
simple_object_xcoff_find_sections (simple_object_read *sobj,
390
				  int (*pfn) (void *, const char *,
391
					      off_t offset, off_t length),
392
				  void *data,
393
				  int *err)
394
{
395
  struct simple_object_xcoff_read *ocr =
396
    (struct simple_object_xcoff_read *) sobj->data;
397
  int u64 = ocr->magic == U64_TOCMAGIC;
398
  size_t scnhdr_size;
399
  unsigned char *scnbuf;
400
  const char *errmsg;
401
  unsigned int (*fetch_32) (const unsigned char *);
402
  ulong_type (*fetch_64) (const unsigned char *);
403
  unsigned int nscns;
404
  char *strtab;
405
  size_t strtab_size;
406
  unsigned int i;
407
 
408
  scnhdr_size = u64 ? SCNHSZ64 : SCNHSZ32;
409
  scnbuf = XNEWVEC (unsigned char, scnhdr_size * ocr->nscns);
410
  if (!simple_object_internal_read (sobj->descriptor,
411
				    sobj->offset + ocr->scnhdr_offset,
412
				    scnbuf, scnhdr_size * ocr->nscns, &errmsg,
413
				    err))
414
    {
415
      XDELETEVEC (scnbuf);
416
      return errmsg;
417
    }
418
 
419
  fetch_32 = simple_object_fetch_big_32;
420
  fetch_64 = simple_object_fetch_big_64;
421
 
422
  nscns = ocr->nscns;
423
  strtab = NULL;
424
  strtab_size = 0;
425
  for (i = 0; i < nscns; ++i)
426
    {
427
      unsigned char *scnhdr;
428
      unsigned char *scnname;
429
      char namebuf[SCNNMLEN + 1];
430
      char *name;
431
      off_t scnptr;
432
      unsigned int size;
433
 
434
      scnhdr = scnbuf + i * scnhdr_size;
435
      scnname = scnhdr + offsetof (struct external_scnhdr, s_name);
436
      memcpy (namebuf, scnname, SCNNMLEN);
437
      namebuf[SCNNMLEN] = '\0';
438
      name = &namebuf[0];
439
      if (namebuf[0] == '/')
440
	{
441
	  size_t strindex;
442
	  char *end;
443
 
444
	  strindex = strtol (namebuf + 1, &end, 10);
445
	  if (*end == '\0')
446
	    {
447
	      /* The real section name is found in the string
448
		 table.  */
449
	      if (strtab == NULL)
450
		{
451
		  strtab = simple_object_xcoff_read_strtab (sobj,
452
							   &strtab_size,
453
							   &errmsg, err);
454
		  if (strtab == NULL)
455
		    {
456
		      XDELETEVEC (scnbuf);
457
		      return errmsg;
458
		    }
459
		}
460
 
461
	      if (strindex < 4 || strindex >= strtab_size)
462
		{
463
		  XDELETEVEC (strtab);
464
		  XDELETEVEC (scnbuf);
465
		  *err = 0;
466
		  return "section string index out of range";
467
		}
468
 
469
	      name = strtab + strindex;
470
	    }
471
	}
472
 
473
      if (u64)
474
	{
475
	  scnptr = fetch_64 (scnhdr + offsetof (struct external_scnhdr,
476
						u.xcoff64.s_scnptr));
477
	  size = fetch_64 (scnhdr + offsetof (struct external_scnhdr,
478
					      u.xcoff64.s_size));
479
	}
480
      else
481
	{
482
	  scnptr = fetch_32 (scnhdr + offsetof (struct external_scnhdr,
483
						u.xcoff32.s_scnptr));
484
	  size = fetch_32 (scnhdr + offsetof (struct external_scnhdr,
485
					      u.xcoff32.s_size));
486
	}
487
 
488
      if (!(*pfn) (data, name, scnptr, size))
489
	break;
490
    }
491
 
492
  if (strtab != NULL)
493
    XDELETEVEC (strtab);
494
  XDELETEVEC (scnbuf);
495
 
496
  return NULL;
497
}
498
 
499
/* Fetch the attributes for an simple_object_read.  */
500
 
501
static void *
502
simple_object_xcoff_fetch_attributes (simple_object_read *sobj,
503
				     const char **errmsg ATTRIBUTE_UNUSED,
504
				     int *err ATTRIBUTE_UNUSED)
505
{
506
  struct simple_object_xcoff_read *ocr =
507
    (struct simple_object_xcoff_read *) sobj->data;
508
  struct simple_object_xcoff_attributes *ret;
509
 
510
  ret = XNEW (struct simple_object_xcoff_attributes);
511
  ret->magic = ocr->magic;
512
  ret->flags = ocr->flags;
513
  return ret;
514
}
515
 
516
/* Release the private data for an simple_object_read.  */
517
 
518
static void
519
simple_object_xcoff_release_read (void *data)
520
{
521
  XDELETE (data);
522
}
523
 
524
/* Compare two attributes structures.  */
525
 
526
static const char *
527
simple_object_xcoff_attributes_merge (void *todata, void *fromdata, int *err)
528
{
529
  struct simple_object_xcoff_attributes *to =
530
    (struct simple_object_xcoff_attributes *) todata;
531
  struct simple_object_xcoff_attributes *from =
532
    (struct simple_object_xcoff_attributes *) fromdata;
533
 
534
  if (to->magic != from->magic)
535
    {
536
      *err = 0;
537
      return "XCOFF object format mismatch";
538
    }
539
  return NULL;
540
}
541
 
542
/* Release the private data for an attributes structure.  */
543
 
544
static void
545
simple_object_xcoff_release_attributes (void *data)
546
{
547
  XDELETE (data);
548
}
549
 
550
/* Prepare to write out a file.  */
551
 
552
static void *
553
simple_object_xcoff_start_write (void *attributes_data,
554
				const char **errmsg ATTRIBUTE_UNUSED,
555
				int *err ATTRIBUTE_UNUSED)
556
{
557
  struct simple_object_xcoff_attributes *attrs =
558
    (struct simple_object_xcoff_attributes *) attributes_data;
559
  struct simple_object_xcoff_attributes *ret;
560
 
561
  /* We're just going to record the attributes, but we need to make a
562
     copy because the user may delete them.  */
563
  ret = XNEW (struct simple_object_xcoff_attributes);
564
  *ret = *attrs;
565
  return ret;
566
}
567
 
568
/* Write out a XCOFF filehdr.  */
569
 
570
static int
571
simple_object_xcoff_write_filehdr (simple_object_write *sobj, int descriptor,
572
				  unsigned int nscns, size_t symtab_offset,
573
				  unsigned int nsyms, const char **errmsg,
574
				  int *err)
575
{
576
  struct simple_object_xcoff_attributes *attrs =
577
    (struct simple_object_xcoff_attributes *) sobj->data;
578
  int u64 = attrs->magic == U64_TOCMAGIC;
579
  unsigned char hdrbuf[sizeof (struct external_filehdr)];
580
  unsigned char *hdr;
581
  void (*set_16) (unsigned char *, unsigned short);
582
  void (*set_32) (unsigned char *, unsigned int);
583
  void (*set_64) (unsigned char *, ulong_type);
584
 
585
  hdr = &hdrbuf[0];
586
 
587
  set_16 = simple_object_set_big_16;
588
  set_32 = simple_object_set_big_32;
589
  set_64 = simple_object_set_big_64;
590
 
591
  memset (hdr, 0, sizeof (struct external_filehdr));
592
 
593
  set_16 (hdr + offsetof (struct external_filehdr, f_magic), attrs->magic);
594
  set_16 (hdr + offsetof (struct external_filehdr, f_nscns), nscns);
595
  /* f_timdat left as zero.  */
596
  if (u64)
597
    {
598
      set_64 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_symptr),
599
	      symtab_offset);
600
      set_32 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_nsyms),
601
	      nsyms);
602
      /* f_opthdr left as zero.  */
603
      set_16 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_flags),
604
	      attrs->flags);
605
    }
606
  else
607
    {
608
      set_32 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_symptr),
609
	      symtab_offset);
610
      set_32 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_nsyms),
611
	      nsyms);
612
      /* f_opthdr left as zero.  */
613
      set_16 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_flags),
614
	      attrs->flags);
615
    }
616
 
617
  return simple_object_internal_write (descriptor, 0, hdrbuf,
618
				       sizeof (struct external_filehdr),
619
				       errmsg, err);
620
}
621
 
622
/* Write out a XCOFF section header.  */
623
 
624
static int
625
simple_object_xcoff_write_scnhdr (simple_object_write *sobj,
626
				  int descriptor,
627
				  const char *name, size_t *name_offset,
628
				  off_t scnhdr_offset, size_t scnsize,
629
				  off_t offset, unsigned int align,
630
				  const char **errmsg, int *err)
631
{
632
  struct simple_object_xcoff_read *ocr =
633
    (struct simple_object_xcoff_read *) sobj->data;
634
  int u64 = ocr->magic == U64_TOCMAGIC;
635
  void (*set_32) (unsigned char *, unsigned int);
636
  void (*set_64) (unsigned char *, unsigned int);
637
  unsigned char hdrbuf[sizeof (struct external_scnhdr)];
638
  unsigned char *hdr;
639
  size_t namelen;
640
  unsigned int flags;
641
 
642
  set_32 = simple_object_set_big_32;
643
  set_64 = simple_object_set_big_32;
644
 
645
  memset (hdrbuf, 0, sizeof hdrbuf);
646
  hdr = &hdrbuf[0];
647
 
648
  namelen = strlen (name);
649
  if (namelen <= SCNNMLEN)
650
    strncpy ((char *) hdr + offsetof (struct external_scnhdr, s_name),
651
	     name, SCNNMLEN);
652
  else
653
    {
654
      snprintf ((char *) hdr + offsetof (struct external_scnhdr, s_name),
655
		SCNNMLEN, "/%lu", (unsigned long) *name_offset);
656
      *name_offset += namelen + 1;
657
    }
658
 
659
  /* s_paddr left as zero.  */
660
  /* s_vaddr left as zero.  */
661
  if (u64)
662
    {
663
      set_64 (hdr + offsetof (struct external_scnhdr, u.xcoff64.s_size),
664
	      scnsize);
665
      set_64 (hdr + offsetof (struct external_scnhdr, u.xcoff64.s_scnptr),
666
	      offset);
667
    }
668
  else
669
    {
670
      set_32 (hdr + offsetof (struct external_scnhdr, u.xcoff32.s_size),
671
	      scnsize);
672
      set_32 (hdr + offsetof (struct external_scnhdr, u.xcoff32.s_scnptr),
673
	      offset);
674
    }
675
  /* s_relptr left as zero.  */
676
  /* s_lnnoptr left as zero.  */
677
  /* s_nreloc left as zero.  */
678
  /* s_nlnno left as zero.  */
679
  flags = STYP_DATA;
680
  if (align > 13)
681
    align = 13;
682
  if (u64)
683
    set_32 (hdr + offsetof (struct external_scnhdr, u.xcoff64.s_flags), flags);
684
  else
685
    set_32 (hdr + offsetof (struct external_scnhdr, u.xcoff32.s_flags), flags);
686
 
687
  return simple_object_internal_write (descriptor, scnhdr_offset, hdrbuf,
688
				       u64 ? SCNHSZ64 : SCNHSZ32,
689
				       errmsg, err);
690
}
691
 
692
/* Write out a complete XCOFF file.  */
693
 
694
static const char *
695
simple_object_xcoff_write_to_file (simple_object_write *sobj, int descriptor,
696
				  int *err)
697
{
698
  struct simple_object_xcoff_read *ocr =
699
    (struct simple_object_xcoff_read *) sobj->data;
700
  int u64 = ocr->magic == U64_TOCMAGIC;
701
  unsigned int nscns, secnum;
702
  simple_object_write_section *section;
703
  off_t scnhdr_offset;
704
  size_t symtab_offset;
705
  off_t secsym_offset;
706
  unsigned int nsyms;
707
  size_t offset;
708
  size_t name_offset;
709
  const char *errmsg;
710
  unsigned char strsizebuf[4];
711
  /* The interface doesn't give us access to the name of the input file
712
     yet.  We want to use its basename for the FILE symbol.  This is
713
     what 'gas' uses when told to assemble from stdin.  */
714
  const char *source_filename = "fake";
715
  size_t sflen;
716
  union
717
  {
718
    struct external_syment sym;
719
    union external_auxent aux;
720
  } syms[2];
721
  void (*set_16) (unsigned char *, unsigned short);
722
  void (*set_32) (unsigned char *, unsigned int);
723
 
724
  set_16 = simple_object_set_big_16;
725
  set_32 = simple_object_set_big_32;
726
 
727
  nscns = 0;
728
  for (section = sobj->sections; section != NULL; section = section->next)
729
    ++nscns;
730
 
731
  scnhdr_offset = sizeof (struct external_filehdr) - (u64 ? 4 : 0);
732
  offset = scnhdr_offset + nscns * (u64 ? SCNHSZ64 : SCNHSZ32);
733
  name_offset = 4;
734
  for (section = sobj->sections; section != NULL; section = section->next)
735
    {
736
      size_t mask;
737
      size_t new_offset;
738
      size_t scnsize;
739
      struct simple_object_write_section_buffer *buffer;
740
 
741
      mask = (1U << section->align) - 1;
742
      new_offset = offset & mask;
743
      new_offset &= ~ mask;
744
      while (new_offset > offset)
745
	{
746
	  unsigned char zeroes[16];
747
	  size_t write;
748
 
749
	  memset (zeroes, 0, sizeof zeroes);
750
	  write = new_offset - offset;
751
	  if (write > sizeof zeroes)
752
	    write = sizeof zeroes;
753
	  if (!simple_object_internal_write (descriptor, offset, zeroes, write,
754
					     &errmsg, err))
755
	    return errmsg;
756
	}
757
 
758
      scnsize = 0;
759
      for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
760
	{
761
	  if (!simple_object_internal_write (descriptor, offset + scnsize,
762
					     ((const unsigned char *)
763
					      buffer->buffer),
764
					     buffer->size, &errmsg, err))
765
	    return errmsg;
766
	  scnsize += buffer->size;
767
	}
768
 
769
      if (!simple_object_xcoff_write_scnhdr (sobj, descriptor, section->name,
770
					    &name_offset, scnhdr_offset,
771
					    scnsize, offset, section->align,
772
					    &errmsg, err))
773
	return errmsg;
774
 
775
      scnhdr_offset += u64 ? SCNHSZ64 : SCNHSZ32;
776
      offset += scnsize;
777
    }
778
 
779
  /* Symbol table is always half-word aligned.  */
780
  offset += (offset & 1);
781
  /* There is a file symbol and a section symbol per section,
782
     and each of these has a single auxiliary symbol following.  */
783
  nsyms = 2 * (nscns + 1);
784
  symtab_offset = offset;
785
  /* Advance across space reserved for symbol table to locate
786
     start of string table.  */
787
  offset += nsyms * SYMESZ;
788
 
789
  /* Write out file symbol.  */
790
  memset (&syms[0], 0, sizeof (syms));
791
  if (!u64)
792
    strcpy ((char *)&syms[0].sym.u.xcoff32.n.n_name[0], ".file");
793
  set_16 (&syms[0].sym.n_scnum[0], N_DEBUG);
794
  set_16 (&syms[0].sym.n_type[0], IMAGE_SYM_TYPE);
795
  syms[0].sym.n_sclass[0] = C_FILE;
796
  syms[0].sym.n_numaux[0] = 1;
797
  /* The name need not be nul-terminated if it fits into the x_fname field
798
     directly, but must be if it has to be placed into the string table.  */
799
  sflen = strlen (source_filename);
800
  if (sflen <= FILNMLEN)
801
    memcpy (&syms[1].aux.x_file.x_fname[0], source_filename, sflen);
802
  else
803
    {
804
      set_32 (&syms[1].aux.x_file._x.x_offset[0], name_offset);
805
      if (!simple_object_internal_write (descriptor, offset + name_offset,
806
					 ((const unsigned char *)
807
					  source_filename),
808
					 sflen + 1, &errmsg, err))
809
	return errmsg;
810
      name_offset += strlen (source_filename) + 1;
811
    }
812
  if (!simple_object_internal_write (descriptor, symtab_offset,
813
				     (const unsigned char *) &syms[0],
814
				     sizeof (syms), &errmsg, err))
815
    return errmsg;
816
 
817
  /* Write the string table length, followed by the strings and section
818
     symbols in step with each other.  */
819
  set_32 (strsizebuf, name_offset);
820
  if (!simple_object_internal_write (descriptor, offset, strsizebuf, 4,
821
				     &errmsg, err))
822
    return errmsg;
823
 
824
  name_offset = 4;
825
  secsym_offset = symtab_offset + sizeof (syms);
826
  memset (&syms[0], 0, sizeof (syms));
827
  set_16 (&syms[0].sym.n_type[0], IMAGE_SYM_TYPE);
828
  syms[0].sym.n_sclass[0] = C_STAT;
829
  syms[0].sym.n_numaux[0] = 1;
830
  secnum = 1;
831
 
832
  for (section = sobj->sections; section != NULL; section = section->next)
833
    {
834
      size_t namelen;
835
      size_t scnsize;
836
      struct simple_object_write_section_buffer *buffer;
837
 
838
      namelen = strlen (section->name);
839
      set_16 (&syms[0].sym.n_scnum[0], secnum++);
840
      scnsize = 0;
841
      for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
842
	scnsize += buffer->size;
843
      set_32 (&syms[1].aux.x_scn.x_scnlen[0], scnsize);
844
      if (namelen > SCNNMLEN)
845
	{
846
	  set_32 (&syms[0].sym.u.xcoff32.n.n.n_zeroes[0], 0);
847
	  set_32 (&syms[0].sym.u.xcoff32.n.n.n_offset[0], name_offset);
848
	  if (!simple_object_internal_write (descriptor, offset + name_offset,
849
					     ((const unsigned char *)
850
					      section->name),
851
					     namelen + 1, &errmsg, err))
852
	    return errmsg;
853
	  name_offset += namelen + 1;
854
	}
855
      else
856
	{
857
	  memcpy (&syms[0].sym.u.xcoff32.n.n_name[0], section->name,
858
		  strlen (section->name));
859
	  memset (&syms[0].sym.u.xcoff32.n.n_name[strlen (section->name)], 0,
860
		  N_SYMNMLEN - strlen (section->name));
861
	}
862
 
863
      if (!simple_object_internal_write (descriptor, secsym_offset,
864
					 (const unsigned char *) &syms[0],
865
					 sizeof (syms), &errmsg, err))
866
	return errmsg;
867
      secsym_offset += sizeof (syms);
868
    }
869
 
870
  if (!simple_object_xcoff_write_filehdr (sobj, descriptor, nscns,
871
					 symtab_offset, nsyms, &errmsg, err))
872
    return errmsg;
873
 
874
  return NULL;
875
}
876
 
877
/* Release the private data for an simple_object_write structure.  */
878
 
879
static void
880
simple_object_xcoff_release_write (void *data)
881
{
882
  XDELETE (data);
883
}
884
 
885
/* The XCOFF functions.  */
886
 
887
const struct simple_object_functions simple_object_xcoff_functions =
888
{
889
  simple_object_xcoff_match,
890
  simple_object_xcoff_find_sections,
891
  simple_object_xcoff_fetch_attributes,
892
  simple_object_xcoff_release_read,
893
  simple_object_xcoff_attributes_merge,
894
  simple_object_xcoff_release_attributes,
895
  simple_object_xcoff_start_write,
896
  simple_object_xcoff_write_to_file,
897
  simple_object_xcoff_release_write
898
};