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 COFF 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 
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
/* COFF structures and constants.  */
46
 
47
/* COFF 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
  unsigned char f_symptr[4];	/* file pointer to symtab	*/
55
  unsigned char f_nsyms[4];	/* number of symtab entries	*/
56
  unsigned char f_opthdr[2];	/* sizeof(optional hdr)		*/
57
  unsigned char f_flags[2];	/* flags			*/
58
};
59
 
60
/* Bits for filehdr f_flags field.  */
61
 
62
#define F_EXEC			(0x0002)
63
#define IMAGE_FILE_SYSTEM	(0x1000)
64
#define IMAGE_FILE_DLL		(0x2000)
65
 
66
/* COFF section header.  */
67
 
68
struct external_scnhdr
69
{
70
  unsigned char s_name[8];	/* section name				*/
71
  unsigned char s_paddr[4];	/* physical address, aliased s_nlib 	*/
72
  unsigned char s_vaddr[4];	/* virtual address			*/
73
  unsigned char s_size[4];	/* section size				*/
74
  unsigned char s_scnptr[4];	/* file ptr to raw data for section 	*/
75
  unsigned char s_relptr[4];	/* file ptr to relocation		*/
76
  unsigned char s_lnnoptr[4];	/* file ptr to line numbers		*/
77
  unsigned char s_nreloc[2];	/* number of relocation entries		*/
78
  unsigned char s_nlnno[2];	/* number of line number entries	*/
79
  unsigned char s_flags[4];	/* flags				*/
80
};
81
 
82
/* The length of the s_name field in struct external_scnhdr.  */
83
 
84
#define SCNNMLEN (8)
85
 
86
/* Bits for scnhdr s_flags field.  This includes some bits defined
87
   only for PE.  This may need to be moved into coff_magic.  */
88
 
89
#define STYP_DATA			(1 << 6)
90
#define IMAGE_SCN_MEM_DISCARDABLE	(1 << 25)
91
#define IMAGE_SCN_MEM_SHARED		(1 << 28)
92
#define IMAGE_SCN_MEM_READ		(1 << 30)
93
 
94
#define IMAGE_SCN_ALIGN_POWER_BIT_POS	     20
95
#define IMAGE_SCN_ALIGN_POWER_CONST(val)     \
96
  (((val) + 1) << IMAGE_SCN_ALIGN_POWER_BIT_POS)
97
 
98
/* COFF symbol table entry.  */
99
 
100
#define E_SYMNMLEN	8	/* # characters in a symbol name	*/
101
 
102
struct external_syment
103
{
104
  union
105
  {
106
    unsigned char e_name[E_SYMNMLEN];
107
 
108
    struct
109
    {
110
      unsigned char e_zeroes[4];
111
      unsigned char e_offset[4];
112
    } e;
113
  } e;
114
 
115
  unsigned char e_value[4];
116
  unsigned char e_scnum[2];
117
  unsigned char e_type[2];
118
  unsigned char e_sclass[1];
119
  unsigned char e_numaux[1];
120
};
121
 
122
/* Length allowed for filename in aux sym format 4.  */
123
 
124
#define E_FILNMLEN	18
125
 
126
/* Omits x_sym and other unused variants.  */
127
 
128
union external_auxent
129
{
130
  /* Aux sym format 4: file.  */
131
  union
132
  {
133
    char x_fname[E_FILNMLEN];
134
    struct
135
    {
136
      unsigned char x_zeroes[4];
137
      unsigned char x_offset[4];
138
    } x_n;
139
  } x_file;
140
  /* Aux sym format 5: section.  */
141
  struct
142
  {
143
    unsigned char x_scnlen[4];		/* section length		*/
144
    unsigned char x_nreloc[2];		/* # relocation entries		*/
145
    unsigned char x_nlinno[2];		/* # line numbers		*/
146
    unsigned char x_checksum[4];	/* section COMDAT checksum	*/
147
    unsigned char x_associated[2];	/* COMDAT assoc section index	*/
148
    unsigned char x_comdat[1];		/* COMDAT selection number	*/
149
  } x_scn;
150
};
151
 
152
/* Symbol-related constants.  */
153
 
154
#define IMAGE_SYM_DEBUG		(-2)
155
#define IMAGE_SYM_TYPE_NULL	(0)
156
#define IMAGE_SYM_DTYPE_NULL	(0)
157
#define IMAGE_SYM_CLASS_STATIC	(3)
158
#define IMAGE_SYM_CLASS_FILE	(103)
159
 
160
#define IMAGE_SYM_TYPE \
161
  ((IMAGE_SYM_DTYPE_NULL << 4) | IMAGE_SYM_TYPE_NULL)
162
 
163
/* Private data for an simple_object_read.  */
164
 
165
struct simple_object_coff_read
166
{
167
  /* Magic number.  */
168
  unsigned short magic;
169
  /* Whether the file is big-endian.  */
170
  unsigned char is_big_endian;
171
  /* Number of sections.  */
172
  unsigned short nscns;
173
  /* File offset of symbol table.  */
174
  off_t symptr;
175
  /* Number of symbol table entries.  */
176
  unsigned int nsyms;
177
  /* Flags.  */
178
  unsigned short flags;
179
  /* Offset of section headers in file.  */
180
  off_t scnhdr_offset;
181
};
182
 
183
/* Private data for an simple_object_attributes.  */
184
 
185
struct simple_object_coff_attributes
186
{
187
  /* Magic number.  */
188
  unsigned short magic;
189
  /* Whether the file is big-endian.  */
190
  unsigned char is_big_endian;
191
  /* Flags.  */
192
  unsigned short flags;
193
};
194
 
195
/* There is no magic number which indicates a COFF file as opposed to
196
   any other sort of file.  Instead, each COFF file starts with a
197
   two-byte magic number which also indicates the type of the target.
198
   This struct holds a magic number as well as characteristics of that
199
   COFF format.  */
200
 
201
struct coff_magic_struct
202
{
203
  /* Magic number.  */
204
  unsigned short magic;
205
  /* Whether this magic number is for a big-endian file.  */
206
  unsigned char is_big_endian;
207
  /* Flag bits, in the f_flags fields, which indicates that this file
208
     is not a relocatable object file.  There is no flag which
209
     specifically indicates a relocatable object file, it is only
210
     implied by the absence of these flags.  */
211
  unsigned short non_object_flags;
212
};
213
 
214
/* This is a list of the COFF magic numbers which we recognize, namely
215
   the ones used on Windows.  More can be added as needed.  */
216
 
217
static const struct coff_magic_struct coff_magic[] =
218
{
219
  /* i386.  */
220
  { 0x14c, 0, F_EXEC | IMAGE_FILE_SYSTEM | IMAGE_FILE_DLL },
221
  /* x86_64.  */
222
  { 0x8664, 0, F_EXEC | IMAGE_FILE_SYSTEM | IMAGE_FILE_DLL }
223
};
224
 
225
/* See if we have a COFF file.  */
226
 
227
static void *
228
simple_object_coff_match (unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN],
229
			  int descriptor, off_t offset,
230
			  const char *segment_name ATTRIBUTE_UNUSED,
231
			  const char **errmsg, int *err)
232
{
233
  size_t c;
234
  unsigned short magic_big;
235
  unsigned short magic_little;
236
  unsigned short magic;
237
  size_t i;
238
  int is_big_endian;
239
  unsigned short (*fetch_16) (const unsigned char *);
240
  unsigned int (*fetch_32) (const unsigned char *);
241
  unsigned char hdrbuf[sizeof (struct external_filehdr)];
242
  unsigned short flags;
243
  struct simple_object_coff_read *ocr;
244
 
245
  c = sizeof (coff_magic) / sizeof (coff_magic[0]);
246
  magic_big = simple_object_fetch_big_16 (header);
247
  magic_little = simple_object_fetch_little_16 (header);
248
  for (i = 0; i < c; ++i)
249
    {
250
      if (coff_magic[i].is_big_endian
251
	  ? coff_magic[i].magic == magic_big
252
	  : coff_magic[i].magic == magic_little)
253
	break;
254
    }
255
  if (i >= c)
256
    {
257
      *errmsg = NULL;
258
      *err = 0;
259
      return NULL;
260
    }
261
  is_big_endian = coff_magic[i].is_big_endian;
262
 
263
  magic = is_big_endian ? magic_big : magic_little;
264
  fetch_16 = (is_big_endian
265
	      ? simple_object_fetch_big_16
266
	      : simple_object_fetch_little_16);
267
  fetch_32 = (is_big_endian
268
	      ? simple_object_fetch_big_32
269
	      : simple_object_fetch_little_32);
270
 
271
  if (!simple_object_internal_read (descriptor, offset, hdrbuf, sizeof hdrbuf,
272
				    errmsg, err))
273
    return NULL;
274
 
275
  flags = fetch_16 (hdrbuf + offsetof (struct external_filehdr, f_flags));
276
  if ((flags & coff_magic[i].non_object_flags) != 0)
277
    {
278
      *errmsg = "not relocatable object file";
279
      *err = 0;
280
      return NULL;
281
    }
282
 
283
  ocr = XNEW (struct simple_object_coff_read);
284
  ocr->magic = magic;
285
  ocr->is_big_endian = is_big_endian;
286
  ocr->nscns = fetch_16 (hdrbuf + offsetof (struct external_filehdr, f_nscns));
287
  ocr->symptr = fetch_32 (hdrbuf
288
			  + offsetof (struct external_filehdr, f_symptr));
289
  ocr->nsyms = fetch_32 (hdrbuf + offsetof (struct external_filehdr, f_nsyms));
290
  ocr->flags = flags;
291
  ocr->scnhdr_offset = (sizeof (struct external_filehdr)
292
			+ fetch_16 (hdrbuf + offsetof (struct external_filehdr,
293
						       f_opthdr)));
294
 
295
  return (void *) ocr;
296
}
297
 
298
/* Read the string table in a COFF file.  */
299
 
300
static char *
301
simple_object_coff_read_strtab (simple_object_read *sobj, size_t *strtab_size,
302
				const char **errmsg, int *err)
303
{
304
  struct simple_object_coff_read *ocr =
305
    (struct simple_object_coff_read *) sobj->data;
306
  off_t strtab_offset;
307
  unsigned char strsizebuf[4];
308
  size_t strsize;
309
  char *strtab;
310
 
311
  strtab_offset = sobj->offset + ocr->symptr
312
		  + ocr->nsyms * sizeof (struct external_syment);
313
  if (!simple_object_internal_read (sobj->descriptor, strtab_offset,
314
				    strsizebuf, 4, errmsg, err))
315
    return NULL;
316
  strsize = (ocr->is_big_endian
317
	     ? simple_object_fetch_big_32 (strsizebuf)
318
	     : simple_object_fetch_little_32 (strsizebuf));
319
  strtab = XNEWVEC (char, strsize);
320
  if (!simple_object_internal_read (sobj->descriptor, strtab_offset,
321
				    (unsigned char *) strtab, strsize, errmsg,
322
				    err))
323
    {
324
      XDELETEVEC (strtab);
325
      return NULL;
326
    }
327
  *strtab_size = strsize;
328
  return strtab;
329
}
330
 
331
/* Find all sections in a COFF file.  */
332
 
333
static const char *
334
simple_object_coff_find_sections (simple_object_read *sobj,
335
				  int (*pfn) (void *, const char *,
336
					      off_t offset, off_t length),
337
				  void *data,
338
				  int *err)
339
{
340
  struct simple_object_coff_read *ocr =
341
    (struct simple_object_coff_read *) sobj->data;
342
  size_t scnhdr_size;
343
  unsigned char *scnbuf;
344
  const char *errmsg;
345
  unsigned int (*fetch_32) (const unsigned char *);
346
  unsigned int nscns;
347
  char *strtab;
348
  size_t strtab_size;
349
  unsigned int i;
350
 
351
  scnhdr_size = sizeof (struct external_scnhdr);
352
  scnbuf = XNEWVEC (unsigned char, scnhdr_size * ocr->nscns);
353
  if (!simple_object_internal_read (sobj->descriptor,
354
				    sobj->offset + ocr->scnhdr_offset,
355
				    scnbuf, scnhdr_size * ocr->nscns, &errmsg,
356
				    err))
357
    {
358
      XDELETEVEC (scnbuf);
359
      return errmsg;
360
    }
361
 
362
  fetch_32 = (ocr->is_big_endian
363
	      ? simple_object_fetch_big_32
364
	      : simple_object_fetch_little_32);
365
 
366
  nscns = ocr->nscns;
367
  strtab = NULL;
368
  strtab_size = 0;
369
  for (i = 0; i < nscns; ++i)
370
    {
371
      unsigned char *scnhdr;
372
      unsigned char *scnname;
373
      char namebuf[SCNNMLEN + 1];
374
      char *name;
375
      off_t scnptr;
376
      unsigned int size;
377
 
378
      scnhdr = scnbuf + i * scnhdr_size;
379
      scnname = scnhdr + offsetof (struct external_scnhdr, s_name);
380
      memcpy (namebuf, scnname, SCNNMLEN);
381
      namebuf[SCNNMLEN] = '\0';
382
      name = &namebuf[0];
383
      if (namebuf[0] == '/')
384
	{
385
	  size_t strindex;
386
	  char *end;
387
 
388
	  strindex = strtol (namebuf + 1, &end, 10);
389
	  if (*end == '\0')
390
	    {
391
	      /* The real section name is found in the string
392
		 table.  */
393
	      if (strtab == NULL)
394
		{
395
		  strtab = simple_object_coff_read_strtab (sobj,
396
							   &strtab_size,
397
							   &errmsg, err);
398
		  if (strtab == NULL)
399
		    {
400
		      XDELETEVEC (scnbuf);
401
		      return errmsg;
402
		    }
403
		}
404
 
405
	      if (strindex < 4 || strindex >= strtab_size)
406
		{
407
		  XDELETEVEC (strtab);
408
		  XDELETEVEC (scnbuf);
409
		  *err = 0;
410
		  return "section string index out of range";
411
		}
412
 
413
	      name = strtab + strindex;
414
	    }
415
	}
416
 
417
      scnptr = fetch_32 (scnhdr + offsetof (struct external_scnhdr, s_scnptr));
418
      size = fetch_32 (scnhdr + offsetof (struct external_scnhdr, s_size));
419
 
420
      if (!(*pfn) (data, name, scnptr, size))
421
	break;
422
    }
423
 
424
  if (strtab != NULL)
425
    XDELETEVEC (strtab);
426
  XDELETEVEC (scnbuf);
427
 
428
  return NULL;
429
}
430
 
431
/* Fetch the attributes for an simple_object_read.  */
432
 
433
static void *
434
simple_object_coff_fetch_attributes (simple_object_read *sobj,
435
				     const char **errmsg ATTRIBUTE_UNUSED,
436
				     int *err ATTRIBUTE_UNUSED)
437
{
438
  struct simple_object_coff_read *ocr =
439
    (struct simple_object_coff_read *) sobj->data;
440
  struct simple_object_coff_attributes *ret;
441
 
442
  ret = XNEW (struct simple_object_coff_attributes);
443
  ret->magic = ocr->magic;
444
  ret->is_big_endian = ocr->is_big_endian;
445
  ret->flags = ocr->flags;
446
  return ret;
447
}
448
 
449
/* Release the private data for an simple_object_read.  */
450
 
451
static void
452
simple_object_coff_release_read (void *data)
453
{
454
  XDELETE (data);
455
}
456
 
457
/* Compare two attributes structures.  */
458
 
459
static const char *
460
simple_object_coff_attributes_merge (void *todata, void *fromdata, int *err)
461
{
462
  struct simple_object_coff_attributes *to =
463
    (struct simple_object_coff_attributes *) todata;
464
  struct simple_object_coff_attributes *from =
465
    (struct simple_object_coff_attributes *) fromdata;
466
 
467
  if (to->magic != from->magic || to->is_big_endian != from->is_big_endian)
468
    {
469
      *err = 0;
470
      return "COFF object format mismatch";
471
    }
472
  return NULL;
473
}
474
 
475
/* Release the private data for an attributes structure.  */
476
 
477
static void
478
simple_object_coff_release_attributes (void *data)
479
{
480
  XDELETE (data);
481
}
482
 
483
/* Prepare to write out a file.  */
484
 
485
static void *
486
simple_object_coff_start_write (void *attributes_data,
487
				const char **errmsg ATTRIBUTE_UNUSED,
488
				int *err ATTRIBUTE_UNUSED)
489
{
490
  struct simple_object_coff_attributes *attrs =
491
    (struct simple_object_coff_attributes *) attributes_data;
492
  struct simple_object_coff_attributes *ret;
493
 
494
  /* We're just going to record the attributes, but we need to make a
495
     copy because the user may delete them.  */
496
  ret = XNEW (struct simple_object_coff_attributes);
497
  *ret = *attrs;
498
  return ret;
499
}
500
 
501
/* Write out a COFF filehdr.  */
502
 
503
static int
504
simple_object_coff_write_filehdr (simple_object_write *sobj, int descriptor,
505
				  unsigned int nscns, size_t symtab_offset,
506
				  unsigned int nsyms, const char **errmsg,
507
				  int *err)
508
{
509
  struct simple_object_coff_attributes *attrs =
510
    (struct simple_object_coff_attributes *) sobj->data;
511
  unsigned char hdrbuf[sizeof (struct external_filehdr)];
512
  unsigned char *hdr;
513
  void (*set_16) (unsigned char *, unsigned short);
514
  void (*set_32) (unsigned char *, unsigned int);
515
 
516
  hdr = &hdrbuf[0];
517
 
518
  set_16 = (attrs->is_big_endian
519
	    ? simple_object_set_big_16
520
	    : simple_object_set_little_16);
521
  set_32 = (attrs->is_big_endian
522
	    ? simple_object_set_big_32
523
	    : simple_object_set_little_32);
524
 
525
  memset (hdr, 0, sizeof (struct external_filehdr));
526
 
527
  set_16 (hdr + offsetof (struct external_filehdr, f_magic), attrs->magic);
528
  set_16 (hdr + offsetof (struct external_filehdr, f_nscns), nscns);
529
  /* f_timdat left as zero.  */
530
  set_32 (hdr + offsetof (struct external_filehdr, f_symptr), symtab_offset);
531
  set_32 (hdr + offsetof (struct external_filehdr, f_nsyms), nsyms);
532
  /* f_opthdr left as zero.  */
533
  set_16 (hdr + offsetof (struct external_filehdr, f_flags), attrs->flags);
534
 
535
  return simple_object_internal_write (descriptor, 0, hdrbuf,
536
				       sizeof (struct external_filehdr),
537
				       errmsg, err);
538
}
539
 
540
/* Write out a COFF section header.  */
541
 
542
static int
543
simple_object_coff_write_scnhdr (simple_object_write *sobj, int descriptor,
544
				 const char *name, size_t *name_offset,
545
				 off_t scnhdr_offset, size_t scnsize,
546
				 off_t offset, unsigned int align,
547
				 const char **errmsg, int *err)
548
{
549
  struct simple_object_coff_attributes *attrs =
550
    (struct simple_object_coff_attributes *) sobj->data;
551
  void (*set_32) (unsigned char *, unsigned int);
552
  unsigned char hdrbuf[sizeof (struct external_scnhdr)];
553
  unsigned char *hdr;
554
  size_t namelen;
555
  unsigned int flags;
556
 
557
  set_32 = (attrs->is_big_endian
558
	    ? simple_object_set_big_32
559
	    : simple_object_set_little_32);
560
 
561
  memset (hdrbuf, 0, sizeof hdrbuf);
562
  hdr = &hdrbuf[0];
563
 
564
  namelen = strlen (name);
565
  if (namelen <= SCNNMLEN)
566
    strncpy ((char *) hdr + offsetof (struct external_scnhdr, s_name), name,
567
	     SCNNMLEN);
568
  else
569
    {
570
      snprintf ((char *) hdr + offsetof (struct external_scnhdr, s_name),
571
		SCNNMLEN, "/%lu", (unsigned long) *name_offset);
572
      *name_offset += namelen + 1;
573
    }
574
 
575
  /* s_paddr left as zero.  */
576
  /* s_vaddr left as zero.  */
577
  set_32 (hdr + offsetof (struct external_scnhdr, s_size), scnsize);
578
  set_32 (hdr + offsetof (struct external_scnhdr, s_scnptr), offset);
579
  /* s_relptr left as zero.  */
580
  /* s_lnnoptr left as zero.  */
581
  /* s_nreloc left as zero.  */
582
  /* s_nlnno left as zero.  */
583
  flags = (STYP_DATA | IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_MEM_SHARED
584
	   | IMAGE_SCN_MEM_READ);
585
  /* PE can represent alignment up to 13.  */
586
  if (align > 13)
587
    align = 13;
588
  flags |= IMAGE_SCN_ALIGN_POWER_CONST(align);
589
  set_32 (hdr + offsetof (struct external_scnhdr, s_flags), flags);
590
 
591
  return simple_object_internal_write (descriptor, scnhdr_offset, hdrbuf,
592
				       sizeof (struct external_scnhdr),
593
				       errmsg, err);
594
}
595
 
596
/* Write out a complete COFF file.  */
597
 
598
static const char *
599
simple_object_coff_write_to_file (simple_object_write *sobj, int descriptor,
600
				  int *err)
601
{
602
  struct simple_object_coff_attributes *attrs =
603
    (struct simple_object_coff_attributes *) sobj->data;
604
  unsigned int nscns, secnum;
605
  simple_object_write_section *section;
606
  off_t scnhdr_offset;
607
  size_t symtab_offset;
608
  off_t secsym_offset;
609
  unsigned int nsyms;
610
  size_t offset;
611
  size_t name_offset;
612
  const char *errmsg;
613
  unsigned char strsizebuf[4];
614
  /* The interface doesn't give us access to the name of the input file
615
     yet.  We want to use its basename for the FILE symbol.  This is
616
     what 'gas' uses when told to assemble from stdin.  */
617
  const char *source_filename = "fake";
618
  size_t sflen;
619
  union
620
  {
621
    struct external_syment sym;
622
    union external_auxent aux;
623
  } syms[2];
624
  void (*set_16) (unsigned char *, unsigned short);
625
  void (*set_32) (unsigned char *, unsigned int);
626
 
627
  set_16 = (attrs->is_big_endian
628
	    ? simple_object_set_big_16
629
	    : simple_object_set_little_16);
630
  set_32 = (attrs->is_big_endian
631
	    ? simple_object_set_big_32
632
	    : simple_object_set_little_32);
633
 
634
  nscns = 0;
635
  for (section = sobj->sections; section != NULL; section = section->next)
636
    ++nscns;
637
 
638
  scnhdr_offset = sizeof (struct external_filehdr);
639
  offset = scnhdr_offset + nscns * sizeof (struct external_scnhdr);
640
  name_offset = 4;
641
  for (section = sobj->sections; section != NULL; section = section->next)
642
    {
643
      size_t mask;
644
      size_t new_offset;
645
      size_t scnsize;
646
      struct simple_object_write_section_buffer *buffer;
647
 
648
      mask = (1U << section->align) - 1;
649
      new_offset = offset & mask;
650
      new_offset &= ~ mask;
651
      while (new_offset > offset)
652
	{
653
	  unsigned char zeroes[16];
654
	  size_t write;
655
 
656
	  memset (zeroes, 0, sizeof zeroes);
657
	  write = new_offset - offset;
658
	  if (write > sizeof zeroes)
659
	    write = sizeof zeroes;
660
	  if (!simple_object_internal_write (descriptor, offset, zeroes, write,
661
					     &errmsg, err))
662
	    return errmsg;
663
	}
664
 
665
      scnsize = 0;
666
      for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
667
	{
668
	  if (!simple_object_internal_write (descriptor, offset + scnsize,
669
					     ((const unsigned char *)
670
					      buffer->buffer),
671
					     buffer->size, &errmsg, err))
672
	    return errmsg;
673
	  scnsize += buffer->size;
674
	}
675
 
676
      if (!simple_object_coff_write_scnhdr (sobj, descriptor, section->name,
677
					    &name_offset, scnhdr_offset,
678
					    scnsize, offset, section->align,
679
					    &errmsg, err))
680
	return errmsg;
681
 
682
      scnhdr_offset += sizeof (struct external_scnhdr);
683
      offset += scnsize;
684
    }
685
 
686
  /* Symbol table is always half-word aligned.  */
687
  offset += (offset & 1);
688
  /* There is a file symbol and a section symbol per section,
689
     and each of these has a single auxiliary symbol following.  */
690
  nsyms = 2 * (nscns + 1);
691
  symtab_offset = offset;
692
  /* Advance across space reserved for symbol table to locate
693
     start of string table.  */
694
  offset += nsyms * sizeof (struct external_syment);
695
 
696
  /* Write out file symbol.  */
697
  memset (&syms[0], 0, sizeof (syms));
698
  strcpy ((char *)&syms[0].sym.e.e_name[0], ".file");
699
  set_16 (&syms[0].sym.e_scnum[0], IMAGE_SYM_DEBUG);
700
  set_16 (&syms[0].sym.e_type[0], IMAGE_SYM_TYPE);
701
  syms[0].sym.e_sclass[0] = IMAGE_SYM_CLASS_FILE;
702
  syms[0].sym.e_numaux[0] = 1;
703
  /* The name need not be nul-terminated if it fits into the x_fname field
704
     directly, but must be if it has to be placed into the string table.  */
705
  sflen = strlen (source_filename);
706
  if (sflen <= E_FILNMLEN)
707
    memcpy (&syms[1].aux.x_file.x_fname[0], source_filename, sflen);
708
  else
709
    {
710
      set_32 (&syms[1].aux.x_file.x_n.x_offset[0], name_offset);
711
      if (!simple_object_internal_write (descriptor, offset + name_offset,
712
					 ((const unsigned char *)
713
					  source_filename),
714
					 sflen + 1, &errmsg, err))
715
	return errmsg;
716
      name_offset += strlen (source_filename) + 1;
717
    }
718
  if (!simple_object_internal_write (descriptor, symtab_offset,
719
				     (const unsigned char *) &syms[0],
720
				     sizeof (syms), &errmsg, err))
721
    return errmsg;
722
 
723
  /* Write the string table length, followed by the strings and section
724
     symbols in step with each other.  */
725
  set_32 (strsizebuf, name_offset);
726
  if (!simple_object_internal_write (descriptor, offset, strsizebuf, 4,
727
				     &errmsg, err))
728
    return errmsg;
729
 
730
  name_offset = 4;
731
  secsym_offset = symtab_offset + sizeof (syms);
732
  memset (&syms[0], 0, sizeof (syms));
733
  set_16 (&syms[0].sym.e_type[0], IMAGE_SYM_TYPE);
734
  syms[0].sym.e_sclass[0] = IMAGE_SYM_CLASS_STATIC;
735
  syms[0].sym.e_numaux[0] = 1;
736
  secnum = 1;
737
 
738
  for (section = sobj->sections; section != NULL; section = section->next)
739
    {
740
      size_t namelen;
741
      size_t scnsize;
742
      struct simple_object_write_section_buffer *buffer;
743
 
744
      namelen = strlen (section->name);
745
      set_16 (&syms[0].sym.e_scnum[0], secnum++);
746
      scnsize = 0;
747
      for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
748
	scnsize += buffer->size;
749
      set_32 (&syms[1].aux.x_scn.x_scnlen[0], scnsize);
750
      if (namelen > SCNNMLEN)
751
	{
752
	  set_32 (&syms[0].sym.e.e.e_zeroes[0], 0);
753
	  set_32 (&syms[0].sym.e.e.e_offset[0], name_offset);
754
	  if (!simple_object_internal_write (descriptor, offset + name_offset,
755
					     ((const unsigned char *)
756
					      section->name),
757
					     namelen + 1, &errmsg, err))
758
	    return errmsg;
759
	  name_offset += namelen + 1;
760
	}
761
      else
762
	{
763
	  memcpy (&syms[0].sym.e.e_name[0], section->name,
764
		  strlen (section->name));
765
	  memset (&syms[0].sym.e.e_name[strlen (section->name)], 0,
766
		  E_SYMNMLEN - strlen (section->name));
767
	}
768
 
769
      if (!simple_object_internal_write (descriptor, secsym_offset,
770
					 (const unsigned char *) &syms[0],
771
					 sizeof (syms), &errmsg, err))
772
	return errmsg;
773
      secsym_offset += sizeof (syms);
774
    }
775
 
776
  if (!simple_object_coff_write_filehdr (sobj, descriptor, nscns,
777
					 symtab_offset, nsyms, &errmsg, err))
778
    return errmsg;
779
 
780
  return NULL;
781
}
782
 
783
/* Release the private data for an simple_object_write structure.  */
784
 
785
static void
786
simple_object_coff_release_write (void *data)
787
{
788
  XDELETE (data);
789
}
790
 
791
/* The COFF functions.  */
792
 
793
const struct simple_object_functions simple_object_coff_functions =
794
{
795
  simple_object_coff_match,
796
  simple_object_coff_find_sections,
797
  simple_object_coff_fetch_attributes,
798
  simple_object_coff_release_read,
799
  simple_object_coff_attributes_merge,
800
  simple_object_coff_release_attributes,
801
  simple_object_coff_start_write,
802
  simple_object_coff_write_to_file,
803
  simple_object_coff_release_write
804
};