Subversion Repositories Kolibri OS

Rev

Rev 5222 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
5222 serge 1
/* coff object file format
6324 serge 2
   Copyright (C) 1989-2015 Free Software Foundation, Inc.
5222 serge 3
 
4
   This file is part of GAS.
5
 
6
   GAS is free software; you can redistribute it and/or modify
7
   it under the terms of the GNU General Public License as published by
8
   the Free Software Foundation; either version 3, or (at your option)
9
   any later version.
10
 
11
   GAS is distributed in the hope that it will be useful,
12
   but WITHOUT ANY WARRANTY; without even the implied warranty of
13
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
   GNU General Public License for more details.
15
 
16
   You should have received a copy of the GNU General Public License
17
   along with GAS; see the file COPYING.  If not, write to the Free
18
   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
19
   02110-1301, USA.  */
20
 
21
#define OBJ_HEADER "obj-coff.h"
22
 
23
#include "as.h"
24
#include "safe-ctype.h"
25
#include "subsegs.h"
26
#include "struc-symbol.h"
27
 
28
#ifdef TE_PE
29
#include "coff/pe.h"
30
#endif
31
 
32
#ifdef OBJ_XCOFF
33
#include "coff/xcoff.h"
34
#endif
35
 
36
#define streq(a,b)     (strcmp ((a), (b)) == 0)
37
#define strneq(a,b,n)  (strncmp ((a), (b), (n)) == 0)
38
 
39
/* I think this is probably always correct.  */
40
#ifndef KEEP_RELOC_INFO
41
#define KEEP_RELOC_INFO
42
#endif
43
 
44
/* obj_coff_section will use this macro to set a new section's
45
   attributes when a directive has no valid flags or the "w" flag is
46
   used.  This default should be appropriate for most.  */
47
#ifndef TC_COFF_SECTION_DEFAULT_ATTRIBUTES
48
#define TC_COFF_SECTION_DEFAULT_ATTRIBUTES (SEC_LOAD | SEC_DATA)
49
#endif
50
 
51
/* This is used to hold the symbol built by a sequence of pseudo-ops
52
   from .def and .endef.  */
53
static symbolS *def_symbol_in_progress;
54
#ifdef TE_PE
55
/* PE weak alternate symbols begin with this string.  */
56
static const char weak_altprefix[] = ".weak.";
57
#endif /* TE_PE */
58
 
59
#include "obj-coff-seh.c"
60
 
61
typedef struct
62
  {
63
    unsigned long chunk_size;
64
    unsigned long element_size;
65
    unsigned long size;
66
    char *data;
67
    unsigned long pointer;
68
  }
69
stack;
70
 
71
 
72
/* Stack stuff.  */
73
 
74
static stack *
75
stack_init (unsigned long chunk_size,
76
	    unsigned long element_size)
77
{
78
  stack *st;
79
 
80
  st = malloc (sizeof (* st));
81
  if (!st)
82
    return NULL;
83
  st->data = malloc (chunk_size);
84
  if (!st->data)
85
    {
86
      free (st);
87
      return NULL;
88
    }
89
  st->pointer = 0;
90
  st->size = chunk_size;
91
  st->chunk_size = chunk_size;
92
  st->element_size = element_size;
93
  return st;
94
}
95
 
96
static char *
97
stack_push (stack *st, char *element)
98
{
99
  if (st->pointer + st->element_size >= st->size)
100
    {
101
      st->size += st->chunk_size;
102
      if ((st->data = xrealloc (st->data, st->size)) == NULL)
103
	return NULL;
104
    }
105
  memcpy (st->data + st->pointer, element, st->element_size);
106
  st->pointer += st->element_size;
107
  return st->data + st->pointer;
108
}
109
 
110
static char *
111
stack_pop (stack *st)
112
{
113
  if (st->pointer < st->element_size)
114
    {
115
      st->pointer = 0;
116
      return NULL;
117
    }
118
  st->pointer -= st->element_size;
119
  return st->data + st->pointer;
120
}
121
 
122
/* Maintain a list of the tagnames of the structures.  */
123
 
124
static struct hash_control *tag_hash;
125
 
126
static void
127
tag_init (void)
128
{
129
  tag_hash = hash_new ();
130
}
131
 
132
static void
133
tag_insert (const char *name, symbolS *symbolP)
134
{
135
  const char *error_string;
136
 
137
  if ((error_string = hash_jam (tag_hash, name, (char *) symbolP)))
138
    as_fatal (_("Inserting \"%s\" into structure table failed: %s"),
139
	      name, error_string);
140
}
141
 
142
static symbolS *
143
tag_find (char *name)
144
{
145
  return (symbolS *) hash_find (tag_hash, name);
146
}
147
 
148
static symbolS *
149
tag_find_or_make (char *name)
150
{
151
  symbolS *symbolP;
152
 
153
  if ((symbolP = tag_find (name)) == NULL)
154
    {
155
      symbolP = symbol_new (name, undefined_section,
156
			    0, &zero_address_frag);
157
 
158
      tag_insert (S_GET_NAME (symbolP), symbolP);
159
      symbol_table_insert (symbolP);
160
    }
161
 
162
  return symbolP;
163
}
164
 
165
/* We accept the .bss directive to set the section for backward
166
   compatibility with earlier versions of gas.  */
167
 
168
static void
169
obj_coff_bss (int ignore ATTRIBUTE_UNUSED)
170
{
171
  if (*input_line_pointer == '\n')
172
    subseg_new (".bss", get_absolute_expression ());
173
  else
174
    s_lcomm (0);
175
}
176
 
177
#ifdef TE_PE
178
/* Called from read.c:s_comm after we've parsed .comm symbol, size.
179
   Parse a possible alignment value.  */
180
 
181
static symbolS *
182
obj_coff_common_parse (int ignore ATTRIBUTE_UNUSED, symbolS *symbolP, addressT size)
183
{
184
  addressT align = 0;
185
 
186
  if (*input_line_pointer == ',')
187
    {
188
      align = parse_align (0);
189
      if (align == (addressT) -1)
190
	return NULL;
191
    }
192
 
193
  S_SET_VALUE (symbolP, size);
194
  S_SET_EXTERNAL (symbolP);
195
  S_SET_SEGMENT (symbolP, bfd_com_section_ptr);
196
 
197
  symbol_get_bfdsym (symbolP)->flags |= BSF_OBJECT;
198
 
199
  /* There is no S_SET_ALIGN (symbolP, align) in COFF/PE.
200
     Instead we must add a note to the .drectve section.  */
201
  if (align)
202
    {
203
      segT current_seg = now_seg;
204
      subsegT current_subseg = now_subseg;
205
      flagword oldflags;
206
      asection *sec;
207
      size_t pfxlen, numlen;
208
      char *frag;
209
      char numbuff[20];
210
 
211
      sec = subseg_new (".drectve", 0);
212
      oldflags = bfd_get_section_flags (stdoutput, sec);
213
      if (oldflags == SEC_NO_FLAGS)
214
	{
215
	  if (!bfd_set_section_flags (stdoutput, sec,
216
		TC_COFF_SECTION_DEFAULT_ATTRIBUTES))
217
	    as_warn (_("error setting flags for \"%s\": %s"),
218
		bfd_section_name (stdoutput, sec),
219
		bfd_errmsg (bfd_get_error ()));
220
	}
221
 
222
      /* Emit a string.  Note no NUL-termination.  */
223
      pfxlen = strlen (" -aligncomm:") + 2 + strlen (S_GET_NAME (symbolP)) + 1;
224
      numlen = snprintf (numbuff, sizeof (numbuff), "%d", (int) align);
225
      frag = frag_more (pfxlen + numlen);
226
      (void) sprintf (frag, " -aligncomm:\"%s\",", S_GET_NAME (symbolP));
227
      memcpy (frag + pfxlen, numbuff, numlen);
228
      /* Restore original subseg. */
229
      subseg_set (current_seg, current_subseg);
230
    }
231
 
232
  return symbolP;
233
}
234
 
235
static void
236
obj_coff_comm (int ignore ATTRIBUTE_UNUSED)
237
{
238
  s_comm_internal (ignore, obj_coff_common_parse);
239
}
240
#endif /* TE_PE */
241
 
242
#define GET_FILENAME_STRING(X) \
243
  ((char *) (&((X)->sy_symbol.ost_auxent->x_file.x_n.x_offset))[1])
244
 
245
/* @@ Ick.  */
246
static segT
247
fetch_coff_debug_section (void)
248
{
249
  static segT debug_section;
250
 
251
  if (!debug_section)
252
    {
253
      const asymbol *s;
254
 
255
      s = bfd_make_debug_symbol (stdoutput, NULL, 0);
256
      gas_assert (s != 0);
257
      debug_section = s->section;
258
    }
259
  return debug_section;
260
}
261
 
262
void
263
SA_SET_SYM_ENDNDX (symbolS *sym, symbolS *val)
264
{
265
  combined_entry_type *entry, *p;
266
 
267
  entry = &coffsymbol (symbol_get_bfdsym (sym))->native[1];
268
  p = coffsymbol (symbol_get_bfdsym (val))->native;
269
  entry->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.p = p;
270
  entry->fix_end = 1;
271
}
272
 
273
static void
274
SA_SET_SYM_TAGNDX (symbolS *sym, symbolS *val)
275
{
276
  combined_entry_type *entry, *p;
277
 
278
  entry = &coffsymbol (symbol_get_bfdsym (sym))->native[1];
279
  p = coffsymbol (symbol_get_bfdsym (val))->native;
280
  entry->u.auxent.x_sym.x_tagndx.p = p;
281
  entry->fix_tag = 1;
282
}
283
 
284
static int
285
S_GET_DATA_TYPE (symbolS *sym)
286
{
287
  return coffsymbol (symbol_get_bfdsym (sym))->native->u.syment.n_type;
288
}
289
 
290
int
291
S_SET_DATA_TYPE (symbolS *sym, int val)
292
{
293
  coffsymbol (symbol_get_bfdsym (sym))->native->u.syment.n_type = val;
294
  return val;
295
}
296
 
297
int
298
S_GET_STORAGE_CLASS (symbolS *sym)
299
{
300
  return coffsymbol (symbol_get_bfdsym (sym))->native->u.syment.n_sclass;
301
}
302
 
303
int
304
S_SET_STORAGE_CLASS (symbolS *sym, int val)
305
{
306
  coffsymbol (symbol_get_bfdsym (sym))->native->u.syment.n_sclass = val;
307
  return val;
308
}
309
 
310
/* Merge a debug symbol containing debug information into a normal symbol.  */
311
 
312
static void
313
c_symbol_merge (symbolS *debug, symbolS *normal)
314
{
315
  S_SET_DATA_TYPE (normal, S_GET_DATA_TYPE (debug));
316
  S_SET_STORAGE_CLASS (normal, S_GET_STORAGE_CLASS (debug));
317
 
318
  if (S_GET_NUMBER_AUXILIARY (debug) > S_GET_NUMBER_AUXILIARY (normal))
319
    /* Take the most we have.  */
320
    S_SET_NUMBER_AUXILIARY (normal, S_GET_NUMBER_AUXILIARY (debug));
321
 
322
  if (S_GET_NUMBER_AUXILIARY (debug) > 0)
323
    /* Move all the auxiliary information.  */
324
    memcpy (SYM_AUXINFO (normal), SYM_AUXINFO (debug),
325
	    (S_GET_NUMBER_AUXILIARY (debug)
326
	     * sizeof (*SYM_AUXINFO (debug))));
327
 
328
  /* Move the debug flags.  */
329
  SF_SET_DEBUG_FIELD (normal, SF_GET_DEBUG_FIELD (debug));
330
}
331
 
332
void
333
c_dot_file_symbol (const char *filename, int appfile ATTRIBUTE_UNUSED)
334
{
335
  symbolS *symbolP;
336
 
337
  /* BFD converts filename to a .file symbol with an aux entry.  It
338
     also handles chaining.  */
339
  symbolP = symbol_new (filename, bfd_abs_section_ptr, 0, &zero_address_frag);
340
 
341
  S_SET_STORAGE_CLASS (symbolP, C_FILE);
342
  S_SET_NUMBER_AUXILIARY (symbolP, 1);
343
 
344
  symbol_get_bfdsym (symbolP)->flags = BSF_DEBUGGING;
345
 
346
#ifndef NO_LISTING
347
  {
348
    extern int listing;
349
 
350
    if (listing)
351
      listing_source_file (filename);
352
  }
353
#endif
354
 
355
  /* Make sure that the symbol is first on the symbol chain.  */
356
  if (symbol_rootP != symbolP)
357
    {
358
      symbol_remove (symbolP, &symbol_rootP, &symbol_lastP);
359
      symbol_insert (symbolP, symbol_rootP, &symbol_rootP, &symbol_lastP);
360
    }
361
}
362
 
363
/* Line number handling.  */
364
 
365
struct line_no
366
{
367
  struct line_no *next;
368
  fragS *frag;
369
  alent l;
370
};
371
 
372
int coff_line_base;
373
 
374
/* Symbol of last function, which we should hang line#s off of.  */
375
static symbolS *line_fsym;
376
 
377
#define in_function()		(line_fsym != 0)
378
#define clear_function()	(line_fsym = 0)
379
#define set_function(F)		(line_fsym = (F), coff_add_linesym (F))
380
 
381
 
382
void
383
coff_obj_symbol_new_hook (symbolS *symbolP)
384
{
385
  long   sz = (OBJ_COFF_MAX_AUXENTRIES + 1) * sizeof (combined_entry_type);
386
  char * s  = xmalloc (sz);
387
 
388
  memset (s, 0, sz);
389
  coffsymbol (symbol_get_bfdsym (symbolP))->native = (combined_entry_type *) s;
6324 serge 390
  coffsymbol (symbol_get_bfdsym (symbolP))->native->is_sym = TRUE;
5222 serge 391
 
392
  S_SET_DATA_TYPE (symbolP, T_NULL);
393
  S_SET_STORAGE_CLASS (symbolP, 0);
394
  S_SET_NUMBER_AUXILIARY (symbolP, 0);
395
 
396
  if (S_IS_STRING (symbolP))
397
    SF_SET_STRING (symbolP);
398
 
399
  if (S_IS_LOCAL (symbolP))
400
    SF_SET_LOCAL (symbolP);
401
}
402
 
403
void
404
coff_obj_symbol_clone_hook (symbolS *newsymP, symbolS *orgsymP)
405
{
406
  long sz = (OBJ_COFF_MAX_AUXENTRIES + 1) * sizeof (combined_entry_type);
407
  combined_entry_type * s = xmalloc (sz);
408
 
409
  memcpy (s, coffsymbol (symbol_get_bfdsym (orgsymP))->native, sz);
410
  coffsymbol (symbol_get_bfdsym (newsymP))->native = s;
411
 
412
  SF_SET (newsymP, SF_GET (orgsymP));
413
}
414
 
415
 
416
/* Handle .ln directives.  */
417
 
418
static symbolS *current_lineno_sym;
419
static struct line_no *line_nos;
420
/* FIXME:  Blindly assume all .ln directives will be in the .text section.  */
421
int coff_n_line_nos;
422
 
423
static void
424
add_lineno (fragS * frag, addressT offset, int num)
425
{
426
  struct line_no * new_line = xmalloc (sizeof (* new_line));
427
 
428
  if (!current_lineno_sym)
429
    abort ();
430
 
431
#ifndef OBJ_XCOFF
432
  /* The native aix assembler accepts negative line number.  */
433
 
434
  if (num <= 0)
435
    {
436
      /* Zero is used as an end marker in the file.  */
437
      as_warn (_("Line numbers must be positive integers\n"));
438
      num = 1;
439
    }
440
#endif /* OBJ_XCOFF */
441
  new_line->next = line_nos;
442
  new_line->frag = frag;
443
  new_line->l.line_number = num;
444
  new_line->l.u.offset = offset;
445
  line_nos = new_line;
446
  coff_n_line_nos++;
447
}
448
 
449
void
450
coff_add_linesym (symbolS *sym)
451
{
452
  if (line_nos)
453
    {
454
      coffsymbol (symbol_get_bfdsym (current_lineno_sym))->lineno =
455
	(alent *) line_nos;
456
      coff_n_line_nos++;
457
      line_nos = 0;
458
    }
459
  current_lineno_sym = sym;
460
}
461
 
462
static void
463
obj_coff_ln (int appline)
464
{
465
  int l;
466
 
467
  if (! appline && def_symbol_in_progress != NULL)
468
    {
469
      as_warn (_(".ln pseudo-op inside .def/.endef: ignored."));
470
      demand_empty_rest_of_line ();
471
      return;
472
    }
473
 
474
  l = get_absolute_expression ();
475
 
476
  /* If there is no lineno symbol, treat a .ln
477
     directive as if it were a .appline directive.  */
478
  if (appline || current_lineno_sym == NULL)
479
    new_logical_line ((char *) NULL, l - 1);
480
  else
481
    add_lineno (frag_now, frag_now_fix (), l);
482
 
483
#ifndef NO_LISTING
484
  {
485
    extern int listing;
486
 
487
    if (listing)
488
      {
489
	if (! appline)
490
	  l += coff_line_base - 1;
491
	listing_source_line (l);
492
      }
493
  }
494
#endif
495
 
496
  demand_empty_rest_of_line ();
497
}
498
 
499
/* .loc is essentially the same as .ln; parse it for assembler
500
   compatibility.  */
501
 
502
static void
503
obj_coff_loc (int ignore ATTRIBUTE_UNUSED)
504
{
505
  int lineno;
506
 
507
  /* FIXME: Why do we need this check?  We need it for ECOFF, but why
508
     do we need it for COFF?  */
509
  if (now_seg != text_section)
510
    {
511
      as_warn (_(".loc outside of .text"));
512
      demand_empty_rest_of_line ();
513
      return;
514
    }
515
 
516
  if (def_symbol_in_progress != NULL)
517
    {
518
      as_warn (_(".loc pseudo-op inside .def/.endef: ignored."));
519
      demand_empty_rest_of_line ();
520
      return;
521
    }
522
 
523
  /* Skip the file number.  */
524
  SKIP_WHITESPACE ();
525
  get_absolute_expression ();
526
  SKIP_WHITESPACE ();
527
 
528
  lineno = get_absolute_expression ();
529
 
530
#ifndef NO_LISTING
531
  {
532
    extern int listing;
533
 
534
    if (listing)
535
      {
536
	lineno += coff_line_base - 1;
537
	listing_source_line (lineno);
538
      }
539
  }
540
#endif
541
 
542
  demand_empty_rest_of_line ();
543
 
544
  add_lineno (frag_now, frag_now_fix (), lineno);
545
}
546
 
547
/* Handle the .ident pseudo-op.  */
548
 
549
static void
550
obj_coff_ident (int ignore ATTRIBUTE_UNUSED)
551
{
552
  segT current_seg = now_seg;
553
  subsegT current_subseg = now_subseg;
554
 
555
#ifdef TE_PE
556
  {
557
    segT sec;
558
 
559
    /* We could put it in .comment, but that creates an extra section
560
       that shouldn't be loaded into memory, which requires linker
561
       changes...  For now, until proven otherwise, use .rdata.  */
562
    sec = subseg_new (".rdata$zzz", 0);
563
    bfd_set_section_flags (stdoutput, sec,
564
			   ((SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA)
565
			    & bfd_applicable_section_flags (stdoutput)));
566
  }
567
#else
568
  subseg_new (".comment", 0);
569
#endif
570
 
571
  stringer (8 + 1);
572
  subseg_set (current_seg, current_subseg);
573
}
574
 
575
/* Handle .def directives.
576
 
577
   One might ask : why can't we symbol_new if the symbol does not
578
   already exist and fill it with debug information.  Because of
579
   the C_EFCN special symbol. It would clobber the value of the
580
   function symbol before we have a chance to notice that it is
581
   a C_EFCN. And a second reason is that the code is more clear this
582
   way. (at least I think it is :-).  */
583
 
584
#define SKIP_SEMI_COLON()	while (*input_line_pointer++ != ';')
585
#define SKIP_WHITESPACES()	while (*input_line_pointer == ' ' || \
586
				       *input_line_pointer == '\t')  \
587
                                  input_line_pointer++;
588
 
589
static void
590
obj_coff_def (int what ATTRIBUTE_UNUSED)
591
{
592
  char name_end;		/* Char after the end of name.  */
593
  char *symbol_name;		/* Name of the debug symbol.  */
594
  char *symbol_name_copy;	/* Temporary copy of the name.  */
595
  unsigned int symbol_name_length;
596
 
597
  if (def_symbol_in_progress != NULL)
598
    {
599
      as_warn (_(".def pseudo-op used inside of .def/.endef: ignored."));
600
      demand_empty_rest_of_line ();
601
      return;
602
    }
603
 
604
  SKIP_WHITESPACES ();
605
 
6324 serge 606
  name_end = get_symbol_name (&symbol_name);
5222 serge 607
  symbol_name_length = strlen (symbol_name);
608
  symbol_name_copy = xmalloc (symbol_name_length + 1);
609
  strcpy (symbol_name_copy, symbol_name);
610
#ifdef tc_canonicalize_symbol_name
611
  symbol_name_copy = tc_canonicalize_symbol_name (symbol_name_copy);
612
#endif
613
 
614
  /* Initialize the new symbol.  */
615
  def_symbol_in_progress = symbol_make (symbol_name_copy);
616
  symbol_set_frag (def_symbol_in_progress, &zero_address_frag);
617
  S_SET_VALUE (def_symbol_in_progress, 0);
618
 
619
  if (S_IS_STRING (def_symbol_in_progress))
620
    SF_SET_STRING (def_symbol_in_progress);
621
 
6324 serge 622
  (void) restore_line_pointer (name_end);
5222 serge 623
 
624
  demand_empty_rest_of_line ();
625
}
626
 
627
static void
628
obj_coff_endef (int ignore ATTRIBUTE_UNUSED)
629
{
630
  symbolS *symbolP = NULL;
631
 
632
  if (def_symbol_in_progress == NULL)
633
    {
634
      as_warn (_(".endef pseudo-op used outside of .def/.endef: ignored."));
635
      demand_empty_rest_of_line ();
636
      return;
637
    }
638
 
639
  /* Set the section number according to storage class.  */
640
  switch (S_GET_STORAGE_CLASS (def_symbol_in_progress))
641
    {
642
    case C_STRTAG:
643
    case C_ENTAG:
644
    case C_UNTAG:
645
      SF_SET_TAG (def_symbol_in_progress);
646
      /* Fall through.  */
647
    case C_FILE:
648
    case C_TPDEF:
649
      SF_SET_DEBUG (def_symbol_in_progress);
650
      S_SET_SEGMENT (def_symbol_in_progress, fetch_coff_debug_section ());
651
      break;
652
 
653
    case C_EFCN:
654
      SF_SET_LOCAL (def_symbol_in_progress);	/* Do not emit this symbol.  */
655
      /* Fall through.  */
656
    case C_BLOCK:
657
      SF_SET_PROCESS (def_symbol_in_progress);	/* Will need processing before writing.  */
658
      /* Fall through.  */
659
    case C_FCN:
660
      {
661
	const char *name;
662
 
663
	S_SET_SEGMENT (def_symbol_in_progress, text_section);
664
 
665
	name = S_GET_NAME (def_symbol_in_progress);
666
	if (name[0] == '.' && name[2] == 'f' && name[3] == '\0')
667
	  {
668
	    switch (name[1])
669
	      {
670
	      case 'b':
671
		/* .bf */
672
		if (! in_function ())
673
		  as_warn (_("`%s' symbol without preceding function"), name);
674
		/* Will need relocating.  */
675
		SF_SET_PROCESS (def_symbol_in_progress);
676
		clear_function ();
677
		break;
678
#ifdef TE_PE
679
	      case 'e':
680
		/* .ef */
681
		/* The MS compilers output the actual endline, not the
682
		   function-relative one... we want to match without
683
		   changing the assembler input.  */
684
		SA_SET_SYM_LNNO (def_symbol_in_progress,
685
				 (SA_GET_SYM_LNNO (def_symbol_in_progress)
686
				  + coff_line_base));
687
		break;
688
#endif
689
	      }
690
	  }
691
      }
692
      break;
693
 
694
#ifdef C_AUTOARG
695
    case C_AUTOARG:
696
#endif /* C_AUTOARG */
697
    case C_AUTO:
698
    case C_REG:
699
    case C_ARG:
700
    case C_REGPARM:
701
    case C_FIELD:
702
 
703
    /* According to the COFF documentation:
704
 
705
       http://osr5doc.sco.com:1996/topics/COFF_SectNumFld.html
706
 
707
       A special section number (-2) marks symbolic debugging symbols,
708
       including structure/union/enumeration tag names, typedefs, and
709
       the name of the file. A section number of -1 indicates that the
710
       symbol has a value but is not relocatable. Examples of
711
       absolute-valued symbols include automatic and register variables,
712
       function arguments, and .eos symbols.
713
 
714
       But from Ian Lance Taylor:
715
 
716
       http://sources.redhat.com/ml/binutils/2000-08/msg00202.html
717
 
718
       the actual tools all marked them as section -1. So the GNU COFF
719
       assembler follows historical COFF assemblers.
720
 
721
       However, it causes problems for djgpp
722
 
723
       http://sources.redhat.com/ml/binutils/2000-08/msg00210.html
724
 
725
       By defining STRICTCOFF, a COFF port can make the assembler to
726
       follow the documented behavior.  */
727
#ifdef STRICTCOFF
728
    case C_MOS:
729
    case C_MOE:
730
    case C_MOU:
731
    case C_EOS:
732
#endif
733
      SF_SET_DEBUG (def_symbol_in_progress);
734
      S_SET_SEGMENT (def_symbol_in_progress, absolute_section);
735
      break;
736
 
737
#ifndef STRICTCOFF
738
    case C_MOS:
739
    case C_MOE:
740
    case C_MOU:
741
    case C_EOS:
742
      S_SET_SEGMENT (def_symbol_in_progress, absolute_section);
743
      break;
744
#endif
745
 
746
    case C_EXT:
747
    case C_WEAKEXT:
748
#ifdef TE_PE
749
    case C_NT_WEAK:
750
#endif
751
    case C_STAT:
752
    case C_LABEL:
753
      /* Valid but set somewhere else (s_comm, s_lcomm, colon).  */
754
      break;
755
 
756
    default:
757
    case C_USTATIC:
758
    case C_EXTDEF:
759
    case C_ULABEL:
760
      as_warn (_("unexpected storage class %d"),
761
	       S_GET_STORAGE_CLASS (def_symbol_in_progress));
762
      break;
763
    }
764
 
765
  /* Now that we have built a debug symbol, try to find if we should
766
     merge with an existing symbol or not.  If a symbol is C_EFCN or
767
     absolute_section or untagged SEG_DEBUG it never merges.  We also
768
     don't merge labels, which are in a different namespace, nor
769
     symbols which have not yet been defined since they are typically
770
     unique, nor do we merge tags with non-tags.  */
771
 
772
  /* Two cases for functions.  Either debug followed by definition or
773
     definition followed by debug.  For definition first, we will
774
     merge the debug symbol into the definition.  For debug first, the
775
     lineno entry MUST point to the definition function or else it
776
     will point off into space when obj_crawl_symbol_chain() merges
777
     the debug symbol into the real symbol.  Therefor, let's presume
778
     the debug symbol is a real function reference.  */
779
 
780
  /* FIXME-SOON If for some reason the definition label/symbol is
781
     never seen, this will probably leave an undefined symbol at link
782
     time.  */
783
 
784
  if (S_GET_STORAGE_CLASS (def_symbol_in_progress) == C_EFCN
785
      || S_GET_STORAGE_CLASS (def_symbol_in_progress) == C_LABEL
786
      || (streq (bfd_get_section_name (stdoutput,
787
				       S_GET_SEGMENT (def_symbol_in_progress)),
788
		 "*DEBUG*")
789
	  && !SF_GET_TAG (def_symbol_in_progress))
790
      || S_GET_SEGMENT (def_symbol_in_progress) == absolute_section
791
      || ! symbol_constant_p (def_symbol_in_progress)
792
      || (symbolP = symbol_find (S_GET_NAME (def_symbol_in_progress))) == NULL
793
      || SF_GET_TAG (def_symbol_in_progress) != SF_GET_TAG (symbolP))
794
    {
795
      /* If it already is at the end of the symbol list, do nothing */
796
      if (def_symbol_in_progress != symbol_lastP)
797
	{
798
	  symbol_remove (def_symbol_in_progress, &symbol_rootP, &symbol_lastP);
799
	  symbol_append (def_symbol_in_progress, symbol_lastP, &symbol_rootP,
800
			 &symbol_lastP);
801
	}
802
    }
803
  else
804
    {
805
      /* This symbol already exists, merge the newly created symbol
806
	 into the old one.  This is not mandatory. The linker can
807
	 handle duplicate symbols correctly. But I guess that it save
808
	 a *lot* of space if the assembly file defines a lot of
809
	 symbols. [loic]  */
810
 
811
      /* The debug entry (def_symbol_in_progress) is merged into the
812
	 previous definition.  */
813
 
814
      c_symbol_merge (def_symbol_in_progress, symbolP);
815
      symbol_remove (def_symbol_in_progress, &symbol_rootP, &symbol_lastP);
816
 
817
      def_symbol_in_progress = symbolP;
818
 
819
      if (SF_GET_FUNCTION (def_symbol_in_progress)
820
	  || SF_GET_TAG (def_symbol_in_progress)
821
	  || S_GET_STORAGE_CLASS (def_symbol_in_progress) == C_STAT)
822
	{
823
	  /* For functions, and tags, and static symbols, the symbol
824
	     *must* be where the debug symbol appears.  Move the
825
	     existing symbol to the current place.  */
826
	  /* If it already is at the end of the symbol list, do nothing.  */
827
	  if (def_symbol_in_progress != symbol_lastP)
828
	    {
829
	      symbol_remove (def_symbol_in_progress, &symbol_rootP, &symbol_lastP);
830
	      symbol_append (def_symbol_in_progress, symbol_lastP, &symbol_rootP, &symbol_lastP);
831
	    }
832
	}
833
    }
834
 
835
  if (SF_GET_TAG (def_symbol_in_progress))
836
    {
837
      symbolS *oldtag;
838
 
839
      oldtag = symbol_find (S_GET_NAME (def_symbol_in_progress));
840
      if (oldtag == NULL || ! SF_GET_TAG (oldtag))
841
	tag_insert (S_GET_NAME (def_symbol_in_progress),
842
		    def_symbol_in_progress);
843
    }
844
 
845
  if (SF_GET_FUNCTION (def_symbol_in_progress))
846
    {
847
      set_function (def_symbol_in_progress);
848
      SF_SET_PROCESS (def_symbol_in_progress);
849
 
850
      if (symbolP == NULL)
851
	/* That is, if this is the first time we've seen the
852
	   function.  */
853
	symbol_table_insert (def_symbol_in_progress);
854
 
855
    }
856
 
857
  def_symbol_in_progress = NULL;
858
  demand_empty_rest_of_line ();
859
}
860
 
861
static void
862
obj_coff_dim (int ignore ATTRIBUTE_UNUSED)
863
{
864
  int d_index;
865
 
866
  if (def_symbol_in_progress == NULL)
867
    {
868
      as_warn (_(".dim pseudo-op used outside of .def/.endef: ignored."));
869
      demand_empty_rest_of_line ();
870
      return;
871
    }
872
 
873
  S_SET_NUMBER_AUXILIARY (def_symbol_in_progress, 1);
874
 
875
  for (d_index = 0; d_index < DIMNUM; d_index++)
876
    {
877
      SKIP_WHITESPACES ();
878
      SA_SET_SYM_DIMEN (def_symbol_in_progress, d_index,
879
			get_absolute_expression ());
880
 
881
      switch (*input_line_pointer)
882
	{
883
	case ',':
884
	  input_line_pointer++;
885
	  break;
886
 
887
	default:
888
	  as_warn (_("badly formed .dim directive ignored"));
889
	  /* Fall through.  */
890
	case '\n':
891
	case ';':
892
	  d_index = DIMNUM;
893
	  break;
894
	}
895
    }
896
 
897
  demand_empty_rest_of_line ();
898
}
899
 
900
static void
901
obj_coff_line (int ignore ATTRIBUTE_UNUSED)
902
{
903
  int this_base;
904
 
905
  if (def_symbol_in_progress == NULL)
906
    {
907
      /* Probably stabs-style line?  */
908
      obj_coff_ln (0);
909
      return;
910
    }
911
 
912
  this_base = get_absolute_expression ();
913
  if (streq (".bf", S_GET_NAME (def_symbol_in_progress)))
914
    coff_line_base = this_base;
915
 
916
  S_SET_NUMBER_AUXILIARY (def_symbol_in_progress, 1);
917
  SA_SET_SYM_LNNO (def_symbol_in_progress, this_base);
918
 
919
  demand_empty_rest_of_line ();
920
 
921
#ifndef NO_LISTING
922
  if (streq (".bf", S_GET_NAME (def_symbol_in_progress)))
923
    {
924
      extern int listing;
925
 
926
      if (listing)
927
	listing_source_line ((unsigned int) this_base);
928
    }
929
#endif
930
}
931
 
932
static void
933
obj_coff_size (int ignore ATTRIBUTE_UNUSED)
934
{
935
  if (def_symbol_in_progress == NULL)
936
    {
937
      as_warn (_(".size pseudo-op used outside of .def/.endef ignored."));
938
      demand_empty_rest_of_line ();
939
      return;
940
    }
941
 
942
  S_SET_NUMBER_AUXILIARY (def_symbol_in_progress, 1);
943
  SA_SET_SYM_SIZE (def_symbol_in_progress, get_absolute_expression ());
944
  demand_empty_rest_of_line ();
945
}
946
 
947
static void
948
obj_coff_scl (int ignore ATTRIBUTE_UNUSED)
949
{
950
  if (def_symbol_in_progress == NULL)
951
    {
952
      as_warn (_(".scl pseudo-op used outside of .def/.endef ignored."));
953
      demand_empty_rest_of_line ();
954
      return;
955
    }
956
 
957
  S_SET_STORAGE_CLASS (def_symbol_in_progress, get_absolute_expression ());
958
  demand_empty_rest_of_line ();
959
}
960
 
961
static void
962
obj_coff_tag (int ignore ATTRIBUTE_UNUSED)
963
{
964
  char *symbol_name;
965
  char name_end;
966
 
967
  if (def_symbol_in_progress == NULL)
968
    {
969
      as_warn (_(".tag pseudo-op used outside of .def/.endef ignored."));
970
      demand_empty_rest_of_line ();
971
      return;
972
    }
973
 
974
  S_SET_NUMBER_AUXILIARY (def_symbol_in_progress, 1);
6324 serge 975
  name_end = get_symbol_name (&symbol_name);
5222 serge 976
 
977
#ifdef tc_canonicalize_symbol_name
978
  symbol_name = tc_canonicalize_symbol_name (symbol_name);
979
#endif
980
 
981
  /* Assume that the symbol referred to by .tag is always defined.
982
     This was a bad assumption.  I've added find_or_make. xoxorich.  */
983
  SA_SET_SYM_TAGNDX (def_symbol_in_progress,
984
		     tag_find_or_make (symbol_name));
985
  if (SA_GET_SYM_TAGNDX (def_symbol_in_progress) == 0L)
986
    as_warn (_("tag not found for .tag %s"), symbol_name);
987
 
988
  SF_SET_TAGGED (def_symbol_in_progress);
989
 
6324 serge 990
  (void) restore_line_pointer (name_end);
5222 serge 991
  demand_empty_rest_of_line ();
992
}
993
 
994
static void
995
obj_coff_type (int ignore ATTRIBUTE_UNUSED)
996
{
997
  if (def_symbol_in_progress == NULL)
998
    {
999
      as_warn (_(".type pseudo-op used outside of .def/.endef ignored."));
1000
      demand_empty_rest_of_line ();
1001
      return;
1002
    }
1003
 
1004
  S_SET_DATA_TYPE (def_symbol_in_progress, get_absolute_expression ());
1005
 
1006
  if (ISFCN (S_GET_DATA_TYPE (def_symbol_in_progress)) &&
1007
      S_GET_STORAGE_CLASS (def_symbol_in_progress) != C_TPDEF)
1008
    SF_SET_FUNCTION (def_symbol_in_progress);
1009
 
1010
  demand_empty_rest_of_line ();
1011
}
1012
 
1013
static void
1014
obj_coff_val (int ignore ATTRIBUTE_UNUSED)
1015
{
1016
  if (def_symbol_in_progress == NULL)
1017
    {
1018
      as_warn (_(".val pseudo-op used outside of .def/.endef ignored."));
1019
      demand_empty_rest_of_line ();
1020
      return;
1021
    }
1022
 
1023
  if (is_name_beginner (*input_line_pointer))
1024
    {
6324 serge 1025
      char *symbol_name;
1026
      char name_end = get_symbol_name (&symbol_name);
5222 serge 1027
 
1028
#ifdef tc_canonicalize_symbol_name
6324 serge 1029
      symbol_name = tc_canonicalize_symbol_name (symbol_name);
5222 serge 1030
#endif
1031
      if (streq (symbol_name, "."))
1032
	{
1033
	  /* If the .val is != from the .def (e.g. statics).  */
1034
	  symbol_set_frag (def_symbol_in_progress, frag_now);
1035
	  S_SET_VALUE (def_symbol_in_progress, (valueT) frag_now_fix ());
1036
	}
1037
      else if (! streq (S_GET_NAME (def_symbol_in_progress), symbol_name))
1038
	{
1039
	  expressionS exp;
1040
 
1041
	  exp.X_op = O_symbol;
1042
	  exp.X_add_symbol = symbol_find_or_make (symbol_name);
1043
	  exp.X_op_symbol = NULL;
1044
	  exp.X_add_number = 0;
1045
	  symbol_set_value_expression (def_symbol_in_progress, &exp);
1046
 
1047
	  /* If the segment is undefined when the forward reference is
1048
	     resolved, then copy the segment id from the forward
1049
	     symbol.  */
1050
	  SF_SET_GET_SEGMENT (def_symbol_in_progress);
1051
 
1052
	  /* FIXME: gcc can generate address expressions here in
1053
	     unusual cases (search for "obscure" in sdbout.c).  We
1054
	     just ignore the offset here, thus generating incorrect
1055
	     debugging information.  We ignore the rest of the line
1056
	     just below.  */
1057
	}
1058
      /* Otherwise, it is the name of a non debug symbol and its value
1059
         will be calculated later.  */
6324 serge 1060
      (void) restore_line_pointer (name_end);
5222 serge 1061
    }
1062
  else
1063
    {
1064
      S_SET_VALUE (def_symbol_in_progress, get_absolute_expression ());
1065
    }
1066
 
1067
  demand_empty_rest_of_line ();
1068
}
1069
 
1070
#ifdef TE_PE
1071
 
1072
/* Return nonzero if name begins with weak alternate symbol prefix.  */
1073
 
1074
static int
1075
weak_is_altname (const char * name)
1076
{
1077
  return strneq (name, weak_altprefix, sizeof (weak_altprefix) - 1);
1078
}
1079
 
1080
/* Return the name of the alternate symbol
1081
   name corresponding to a weak symbol's name.  */
1082
 
1083
static const char *
1084
weak_name2altname (const char * name)
1085
{
1086
  char *alt_name;
1087
 
1088
  alt_name = xmalloc (sizeof (weak_altprefix) + strlen (name));
1089
  strcpy (alt_name, weak_altprefix);
1090
  return strcat (alt_name, name);
1091
}
1092
 
1093
/* Return the name of the weak symbol corresponding to an
1094
   alternate symbol.  */
1095
 
1096
static const char *
1097
weak_altname2name (const char * name)
1098
{
1099
  gas_assert (weak_is_altname (name));
1100
  return xstrdup (name + 6);
1101
}
1102
 
1103
/* Make a weak symbol name unique by
1104
   appending the name of an external symbol.  */
1105
 
1106
static const char *
1107
weak_uniquify (const char * name)
1108
{
1109
  char *ret;
1110
  const char * unique = "";
1111
 
1112
#ifdef TE_PE
1113
  if (an_external_name != NULL)
1114
    unique = an_external_name;
1115
#endif
1116
  gas_assert (weak_is_altname (name));
1117
 
1118
  ret = xmalloc (strlen (name) + strlen (unique) + 2);
1119
  strcpy (ret, name);
1120
  strcat (ret, ".");
1121
  strcat (ret, unique);
1122
  return ret;
1123
}
1124
 
1125
void
1126
pecoff_obj_set_weak_hook (symbolS *symbolP)
1127
{
1128
  symbolS *alternateP;
1129
 
1130
  /* See _Microsoft Portable Executable and Common Object
1131
     File Format Specification_, section 5.5.3.
1132
     Create a symbol representing the alternate value.
1133
     coff_frob_symbol will set the value of this symbol from
1134
     the value of the weak symbol itself.  */
1135
  S_SET_STORAGE_CLASS (symbolP, C_NT_WEAK);
1136
  S_SET_NUMBER_AUXILIARY (symbolP, 1);
1137
  SA_SET_SYM_FSIZE (symbolP, IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY);
1138
 
1139
  alternateP = symbol_find_or_make (weak_name2altname (S_GET_NAME (symbolP)));
1140
  S_SET_EXTERNAL (alternateP);
1141
  S_SET_STORAGE_CLASS (alternateP, C_NT_WEAK);
1142
 
1143
  SA_SET_SYM_TAGNDX (symbolP, alternateP);
1144
}
1145
 
1146
void
1147
pecoff_obj_clear_weak_hook (symbolS *symbolP)
1148
{
1149
  symbolS *alternateP;
1150
 
1151
  S_SET_STORAGE_CLASS (symbolP, 0);
1152
  SA_SET_SYM_FSIZE (symbolP, 0);
1153
 
1154
  alternateP = symbol_find (weak_name2altname (S_GET_NAME (symbolP)));
1155
  S_CLEAR_EXTERNAL (alternateP);
1156
}
1157
 
1158
#endif  /* TE_PE */
1159
 
1160
/* Handle .weak.  This is a GNU extension in formats other than PE. */
1161
 
1162
static void
1163
obj_coff_weak (int ignore ATTRIBUTE_UNUSED)
1164
{
1165
  char *name;
1166
  int c;
1167
  symbolS *symbolP;
1168
 
1169
  do
1170
    {
6324 serge 1171
      c = get_symbol_name (&name);
5222 serge 1172
      if (*name == 0)
1173
	{
1174
	  as_warn (_("badly formed .weak directive ignored"));
1175
	  ignore_rest_of_line ();
1176
	  return;
1177
	}
1178
      c = 0;
1179
      symbolP = symbol_find_or_make (name);
1180
      *input_line_pointer = c;
6324 serge 1181
      SKIP_WHITESPACE_AFTER_NAME ();
5222 serge 1182
      S_SET_WEAK (symbolP);
1183
 
1184
      if (c == ',')
1185
	{
1186
	  input_line_pointer++;
1187
	  SKIP_WHITESPACE ();
1188
	  if (*input_line_pointer == '\n')
1189
	    c = '\n';
1190
	}
1191
 
1192
    }
1193
  while (c == ',');
1194
 
1195
  demand_empty_rest_of_line ();
1196
}
1197
 
1198
void
1199
coff_obj_read_begin_hook (void)
1200
{
1201
  /* These had better be the same.  Usually 18 bytes.  */
1202
  know (sizeof (SYMENT) == sizeof (AUXENT));
1203
  know (SYMESZ == AUXESZ);
1204
  tag_init ();
1205
}
1206
 
1207
symbolS *coff_last_function;
1208
#ifndef OBJ_XCOFF
1209
static symbolS *coff_last_bf;
1210
#endif
1211
 
1212
void
1213
coff_frob_symbol (symbolS *symp, int *punt)
1214
{
1215
  static symbolS *last_tagP;
1216
  static stack *block_stack;
1217
  static symbolS *set_end;
1218
  symbolS *next_set_end = NULL;
1219
 
1220
  if (symp == &abs_symbol)
1221
    {
1222
      *punt = 1;
1223
      return;
1224
    }
1225
 
1226
  if (current_lineno_sym)
1227
    coff_add_linesym (NULL);
1228
 
1229
  if (!block_stack)
1230
    block_stack = stack_init (512, sizeof (symbolS*));
1231
 
1232
#ifdef TE_PE
1233
  if (S_GET_STORAGE_CLASS (symp) == C_NT_WEAK
1234
      && ! S_IS_WEAK (symp)
1235
      && weak_is_altname (S_GET_NAME (symp)))
1236
    {
1237
      /* This is a weak alternate symbol.  All processing of
1238
	 PECOFFweak symbols is done here, through the alternate.  */
1239
      symbolS *weakp = symbol_find_noref (weak_altname2name
1240
					  (S_GET_NAME (symp)), 1);
1241
 
1242
      gas_assert (weakp);
1243
      gas_assert (S_GET_NUMBER_AUXILIARY (weakp) == 1);
1244
 
1245
      if (! S_IS_WEAK (weakp))
1246
	{
1247
	  /* The symbol was turned from weak to strong.  Discard altname.  */
1248
	  *punt = 1;
1249
	  return;
1250
	}
1251
      else if (symbol_equated_p (weakp))
1252
	{
1253
	  /* The weak symbol has an alternate specified; symp is unneeded.  */
1254
	  S_SET_STORAGE_CLASS (weakp, C_NT_WEAK);
1255
	  SA_SET_SYM_TAGNDX (weakp,
1256
	    symbol_get_value_expression (weakp)->X_add_symbol);
1257
 
1258
	  S_CLEAR_EXTERNAL (symp);
1259
	  *punt = 1;
1260
	  return;
1261
	}
1262
      else
1263
	{
1264
	  /* The weak symbol has been assigned an alternate value.
1265
             Copy this value to symp, and set symp as weakp's alternate.  */
1266
	  if (S_GET_STORAGE_CLASS (weakp) != C_NT_WEAK)
1267
	    {
1268
	      S_SET_STORAGE_CLASS (symp, S_GET_STORAGE_CLASS (weakp));
1269
	      S_SET_STORAGE_CLASS (weakp, C_NT_WEAK);
1270
	    }
1271
 
1272
	  if (S_IS_DEFINED (weakp))
1273
	    {
1274
	      /* This is a defined weak symbol.  Copy value information
1275
	         from the weak symbol itself to the alternate symbol.  */
1276
	      symbol_set_value_expression (symp,
1277
					   symbol_get_value_expression (weakp));
1278
	      symbol_set_frag (symp, symbol_get_frag (weakp));
1279
	      S_SET_SEGMENT (symp, S_GET_SEGMENT (weakp));
1280
	    }
1281
	  else
1282
	    {
1283
	      /* This is an undefined weak symbol.
1284
		 Define the alternate symbol to zero.  */
1285
	      S_SET_VALUE (symp, 0);
1286
	      S_SET_SEGMENT (symp, absolute_section);
1287
	    }
1288
 
1289
	  S_SET_NAME (symp, weak_uniquify (S_GET_NAME (symp)));
1290
	  S_SET_STORAGE_CLASS (symp, C_EXT);
1291
 
1292
	  S_SET_VALUE (weakp, 0);
1293
	  S_SET_SEGMENT (weakp, undefined_section);
1294
	}
1295
    }
1296
#else /* TE_PE */
1297
  if (S_IS_WEAK (symp))
1298
    S_SET_STORAGE_CLASS (symp, C_WEAKEXT);
1299
#endif /* TE_PE */
1300
 
1301
  if (!S_IS_DEFINED (symp)
1302
      && !S_IS_WEAK (symp)
1303
      && S_GET_STORAGE_CLASS (symp) != C_STAT)
1304
    S_SET_STORAGE_CLASS (symp, C_EXT);
1305
 
1306
  if (!SF_GET_DEBUG (symp))
1307
    {
1308
      symbolS * real;
1309
 
1310
      if (!SF_GET_LOCAL (symp)
1311
	  && !SF_GET_STATICS (symp)
1312
	  && S_GET_STORAGE_CLASS (symp) != C_LABEL
1313
	  && symbol_constant_p (symp)
1314
	  && (real = symbol_find_noref (S_GET_NAME (symp), 1))
1315
	  && S_GET_STORAGE_CLASS (real) == C_NULL
1316
	  && real != symp)
1317
	{
1318
	  c_symbol_merge (symp, real);
1319
	  *punt = 1;
1320
	  return;
1321
	}
1322
 
1323
      if (!S_IS_DEFINED (symp) && !SF_GET_LOCAL (symp))
1324
	{
1325
	  gas_assert (S_GET_VALUE (symp) == 0);
1326
	  if (S_IS_WEAKREFD (symp))
1327
	    *punt = 1;
1328
	  else
1329
	    S_SET_EXTERNAL (symp);
1330
	}
1331
      else if (S_GET_STORAGE_CLASS (symp) == C_NULL)
1332
	{
1333
	  if (S_GET_SEGMENT (symp) == text_section
1334
	      && symp != seg_info (text_section)->sym)
1335
	    S_SET_STORAGE_CLASS (symp, C_LABEL);
1336
	  else
1337
	    S_SET_STORAGE_CLASS (symp, C_STAT);
1338
	}
1339
 
1340
      if (SF_GET_PROCESS (symp))
1341
	{
1342
	  if (S_GET_STORAGE_CLASS (symp) == C_BLOCK)
1343
	    {
1344
	      if (streq (S_GET_NAME (symp), ".bb"))
1345
		stack_push (block_stack, (char *) &symp);
1346
	      else
1347
		{
1348
		  symbolS *begin;
1349
 
1350
		  begin = *(symbolS **) stack_pop (block_stack);
1351
		  if (begin == 0)
1352
		    as_warn (_("mismatched .eb"));
1353
		  else
1354
		    next_set_end = begin;
1355
		}
1356
	    }
1357
 
1358
	  if (coff_last_function == 0 && SF_GET_FUNCTION (symp)
1359
	      && S_IS_DEFINED (symp))
1360
	    {
1361
	      union internal_auxent *auxp;
1362
 
1363
	      coff_last_function = symp;
1364
	      if (S_GET_NUMBER_AUXILIARY (symp) < 1)
1365
		S_SET_NUMBER_AUXILIARY (symp, 1);
1366
	      auxp = SYM_AUXENT (symp);
1367
	      memset (auxp->x_sym.x_fcnary.x_ary.x_dimen, 0,
1368
		      sizeof (auxp->x_sym.x_fcnary.x_ary.x_dimen));
1369
	    }
1370
 
1371
	  if (S_GET_STORAGE_CLASS (symp) == C_EFCN
1372
	      && S_IS_DEFINED (symp))
1373
	    {
1374
	      if (coff_last_function == 0)
1375
		as_fatal (_("C_EFCN symbol for %s out of scope"),
1376
			  S_GET_NAME (symp));
1377
	      SA_SET_SYM_FSIZE (coff_last_function,
1378
				(long) (S_GET_VALUE (symp)
1379
					- S_GET_VALUE (coff_last_function)));
1380
	      next_set_end = coff_last_function;
1381
	      coff_last_function = 0;
1382
	    }
1383
	}
1384
 
1385
      if (S_IS_EXTERNAL (symp))
1386
	S_SET_STORAGE_CLASS (symp, C_EXT);
1387
      else if (SF_GET_LOCAL (symp))
1388
	*punt = 1;
1389
 
1390
      if (SF_GET_FUNCTION (symp))
1391
	symbol_get_bfdsym (symp)->flags |= BSF_FUNCTION;
1392
    }
1393
 
1394
  /* Double check weak symbols.  */
1395
  if (S_IS_WEAK (symp) && S_IS_COMMON (symp))
1396
    as_bad (_("Symbol `%s' can not be both weak and common"),
1397
	    S_GET_NAME (symp));
1398
 
1399
  if (SF_GET_TAG (symp))
1400
    last_tagP = symp;
1401
  else if (S_GET_STORAGE_CLASS (symp) == C_EOS)
1402
    next_set_end = last_tagP;
1403
 
1404
#ifdef OBJ_XCOFF
1405
  /* This is pretty horrible, but we have to set *punt correctly in
1406
     order to call SA_SET_SYM_ENDNDX correctly.  */
1407
  if (! symbol_used_in_reloc_p (symp)
1408
      && ((symbol_get_bfdsym (symp)->flags & BSF_SECTION_SYM) != 0
1409
	  || (! (S_IS_EXTERNAL (symp) || S_IS_WEAK (symp))
1410
	      && ! symbol_get_tc (symp)->output
1411
	      && S_GET_STORAGE_CLASS (symp) != C_FILE)))
1412
    *punt = 1;
1413
#endif
1414
 
1415
  if (set_end != (symbolS *) NULL
1416
      && ! *punt
1417
      && ((symbol_get_bfdsym (symp)->flags & BSF_NOT_AT_END) != 0
1418
	  || (S_IS_DEFINED (symp)
1419
	      && ! S_IS_COMMON (symp)
1420
	      && (! S_IS_EXTERNAL (symp) || SF_GET_FUNCTION (symp)))))
1421
    {
1422
      SA_SET_SYM_ENDNDX (set_end, symp);
1423
      set_end = NULL;
1424
    }
1425
 
1426
  if (next_set_end != NULL)
1427
    {
1428
      if (set_end != NULL)
1429
	as_warn (_("Warning: internal error: forgetting to set endndx of %s"),
1430
		 S_GET_NAME (set_end));
1431
      set_end = next_set_end;
1432
    }
1433
 
1434
#ifndef OBJ_XCOFF
1435
  if (! *punt
1436
      && S_GET_STORAGE_CLASS (symp) == C_FCN
1437
      && streq (S_GET_NAME (symp), ".bf"))
1438
    {
1439
      if (coff_last_bf != NULL)
1440
	SA_SET_SYM_ENDNDX (coff_last_bf, symp);
1441
      coff_last_bf = symp;
1442
    }
1443
#endif
1444
  if (coffsymbol (symbol_get_bfdsym (symp))->lineno)
1445
    {
1446
      int i;
1447
      struct line_no *lptr;
1448
      alent *l;
1449
 
1450
      lptr = (struct line_no *) coffsymbol (symbol_get_bfdsym (symp))->lineno;
1451
      for (i = 0; lptr; lptr = lptr->next)
1452
	i++;
1453
      lptr = (struct line_no *) coffsymbol (symbol_get_bfdsym (symp))->lineno;
1454
 
1455
      /* We need i entries for line numbers, plus 1 for the first
1456
	 entry which BFD will override, plus 1 for the last zero
1457
	 entry (a marker for BFD).  */
1458
      l = xmalloc ((i + 2) * sizeof (* l));
1459
      coffsymbol (symbol_get_bfdsym (symp))->lineno = l;
1460
      l[i + 1].line_number = 0;
1461
      l[i + 1].u.sym = NULL;
1462
      for (; i > 0; i--)
1463
	{
1464
	  if (lptr->frag)
1465
	    lptr->l.u.offset += lptr->frag->fr_address / OCTETS_PER_BYTE;
1466
	  l[i] = lptr->l;
1467
	  lptr = lptr->next;
1468
	}
1469
    }
1470
}
1471
 
1472
void
1473
coff_adjust_section_syms (bfd *abfd ATTRIBUTE_UNUSED,
1474
			  asection *sec,
1475
			  void * x ATTRIBUTE_UNUSED)
1476
{
1477
  symbolS *secsym;
1478
  segment_info_type *seginfo = seg_info (sec);
1479
  int nlnno, nrelocs = 0;
1480
 
1481
  /* RS/6000 gas creates a .debug section manually in ppc_frob_file in
1482
     tc-ppc.c.  Do not get confused by it.  */
1483
  if (seginfo == NULL)
1484
    return;
1485
 
1486
  if (streq (sec->name, ".text"))
1487
    nlnno = coff_n_line_nos;
1488
  else
1489
    nlnno = 0;
1490
  {
1491
    /* @@ Hope that none of the fixups expand to more than one reloc
1492
       entry...  */
1493
    fixS *fixp = seginfo->fix_root;
1494
    while (fixp)
1495
      {
1496
	if (! fixp->fx_done)
1497
	  nrelocs++;
1498
	fixp = fixp->fx_next;
1499
      }
1500
  }
1501
  if (bfd_get_section_size (sec) == 0
1502
      && nrelocs == 0
1503
      && nlnno == 0
1504
      && sec != text_section
1505
      && sec != data_section
1506
      && sec != bss_section)
1507
    return;
1508
 
1509
  secsym = section_symbol (sec);
1510
  /* This is an estimate; we'll plug in the real value using
1511
     SET_SECTION_RELOCS later */
1512
  SA_SET_SCN_NRELOC (secsym, nrelocs);
1513
  SA_SET_SCN_NLINNO (secsym, nlnno);
1514
}
1515
 
1516
void
1517
coff_frob_file_after_relocs (void)
1518
{
1519
  bfd_map_over_sections (stdoutput, coff_adjust_section_syms, NULL);
1520
}
1521
 
1522
/* Implement the .section pseudo op:
1523
  	.section name {, "flags"}
1524
                  ^         ^
1525
                  |         +--- optional flags: 'b' for bss
1526
                  |                              'i' for info
1527
                  +-- section name               'l' for lib
1528
                                                 'n' for noload
1529
                                                 'o' for over
1530
                                                 'w' for data
1531
  						 'd' (apparently m88k for data)
1532
						 'e' for exclude
1533
                                                 'x' for text
1534
  						 'r' for read-only data
1535
  						 's' for shared data (PE)
1536
						 'y' for noread
1537
					   '0' - '9' for power-of-two alignment (GNU extension).
1538
   But if the argument is not a quoted string, treat it as a
1539
   subsegment number.
1540
 
1541
   Note the 'a' flag is silently ignored.  This allows the same
1542
   .section directive to be parsed in both ELF and COFF formats.  */
1543
 
1544
void
1545
obj_coff_section (int ignore ATTRIBUTE_UNUSED)
1546
{
1547
  /* Strip out the section name.  */
1548
  char *section_name;
1549
  char c;
1550
  int alignment = -1;
1551
  char *name;
1552
  unsigned int exp;
1553
  flagword flags, oldflags;
1554
  asection *sec;
1555
 
1556
  if (flag_mri)
1557
    {
1558
      char type;
1559
 
1560
      s_mri_sect (&type);
1561
      return;
1562
    }
1563
 
6324 serge 1564
  c = get_symbol_name (§ion_name);
5222 serge 1565
  name = xmalloc (input_line_pointer - section_name + 1);
1566
  strcpy (name, section_name);
1567
  *input_line_pointer = c;
6324 serge 1568
  SKIP_WHITESPACE_AFTER_NAME ();
5222 serge 1569
 
1570
  exp = 0;
1571
  flags = SEC_NO_FLAGS;
1572
 
1573
  if (*input_line_pointer == ',')
1574
    {
1575
      ++input_line_pointer;
1576
      SKIP_WHITESPACE ();
1577
      if (*input_line_pointer != '"')
1578
	exp = get_absolute_expression ();
1579
      else
1580
	{
1581
	  unsigned char attr;
1582
	  int readonly_removed = 0;
1583
	  int load_removed = 0;
1584
 
1585
	  while (attr = *++input_line_pointer,
1586
		 attr != '"'
1587
		 && ! is_end_of_line[attr])
1588
	    {
1589
	      if (ISDIGIT (attr))
1590
		{
1591
		  alignment = attr - '0';
1592
		  continue;
1593
		}
1594
	      switch (attr)
1595
		{
1596
		case 'e':
1597
		  /* Exclude section from linking.  */
1598
		  flags |= SEC_EXCLUDE;
1599
		  break;
1600
 
1601
		case 'b':
1602
		  /* Uninitialised data section.  */
1603
		  flags |= SEC_ALLOC;
1604
		  flags &=~ SEC_LOAD;
1605
		  break;
1606
 
1607
		case 'n':
1608
		  /* Section not loaded.  */
1609
		  flags &=~ SEC_LOAD;
1610
		  flags |= SEC_NEVER_LOAD;
1611
		  load_removed = 1;
1612
		  break;
1613
 
1614
		case 's':
1615
		  /* Shared section.  */
1616
		  flags |= SEC_COFF_SHARED;
1617
		  /* Fall through.  */
1618
		case 'd':
1619
		  /* Data section.  */
1620
		  flags |= SEC_DATA;
1621
		  if (! load_removed)
1622
		    flags |= SEC_LOAD;
1623
		  flags &=~ SEC_READONLY;
1624
		  break;
1625
 
1626
		case 'w':
1627
		  /* Writable section.  */
1628
		  flags &=~ SEC_READONLY;
1629
		  readonly_removed = 1;
1630
		  break;
1631
 
1632
		case 'a':
1633
		  /* Ignore.  Here for compatibility with ELF.  */
1634
		  break;
1635
 
1636
		case 'r': /* Read-only section.  Implies a data section.  */
1637
		  readonly_removed = 0;
1638
		  /* Fall through.  */
1639
		case 'x': /* Executable section.  */
1640
		  /* If we are setting the 'x' attribute or if the 'r'
1641
		     attribute is being used to restore the readonly status
1642
		     of a code section (eg "wxr") then set the SEC_CODE flag,
1643
		     otherwise set the SEC_DATA flag.  */
1644
		  flags |= (attr == 'x' || (flags & SEC_CODE) ? SEC_CODE : SEC_DATA);
1645
		  if (! load_removed)
1646
		    flags |= SEC_LOAD;
1647
		  /* Note - the READONLY flag is set here, even for the 'x'
1648
		     attribute in order to be compatible with the MSVC
1649
		     linker.  */
1650
		  if (! readonly_removed)
1651
		    flags |= SEC_READONLY;
1652
		  break;
1653
 
1654
		case 'y':
1655
		  flags |= SEC_COFF_NOREAD | SEC_READONLY;
1656
		  break;
1657
 
1658
		case 'i': /* STYP_INFO */
1659
		case 'l': /* STYP_LIB */
1660
		case 'o': /* STYP_OVER */
1661
		  as_warn (_("unsupported section attribute '%c'"), attr);
1662
		  break;
1663
 
1664
		default:
1665
		  as_warn (_("unknown section attribute '%c'"), attr);
1666
		  break;
1667
		}
1668
	    }
1669
	  if (attr == '"')
1670
	    ++input_line_pointer;
1671
	}
1672
    }
1673
 
1674
  sec = subseg_new (name, (subsegT) exp);
1675
 
1676
  if (alignment >= 0)
1677
    sec->alignment_power = alignment;
1678
 
1679
  oldflags = bfd_get_section_flags (stdoutput, sec);
1680
  if (oldflags == SEC_NO_FLAGS)
1681
    {
1682
      /* Set section flags for a new section just created by subseg_new.
1683
         Provide a default if no flags were parsed.  */
1684
      if (flags == SEC_NO_FLAGS)
1685
	flags = TC_COFF_SECTION_DEFAULT_ATTRIBUTES;
1686
 
1687
#ifdef COFF_LONG_SECTION_NAMES
1688
      /* Add SEC_LINK_ONCE and SEC_LINK_DUPLICATES_DISCARD to .gnu.linkonce
1689
         sections so adjust_reloc_syms in write.c will correctly handle
1690
         relocs which refer to non-local symbols in these sections.  */
1691
      if (strneq (name, ".gnu.linkonce", sizeof (".gnu.linkonce") - 1))
1692
	flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
1693
#endif
1694
 
1695
      if (! bfd_set_section_flags (stdoutput, sec, flags))
1696
	as_warn (_("error setting flags for \"%s\": %s"),
1697
		 bfd_section_name (stdoutput, sec),
1698
		 bfd_errmsg (bfd_get_error ()));
1699
    }
1700
  else if (flags != SEC_NO_FLAGS)
1701
    {
1702
      /* This section's attributes have already been set.  Warn if the
1703
         attributes don't match.  */
1704
      flagword matchflags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE
1705
			     | SEC_DATA | SEC_COFF_SHARED | SEC_NEVER_LOAD
1706
			     | SEC_COFF_NOREAD);
1707
      if ((flags ^ oldflags) & matchflags)
1708
	as_warn (_("Ignoring changed section attributes for %s"), name);
1709
    }
1710
 
1711
  demand_empty_rest_of_line ();
1712
}
1713
 
1714
void
1715
coff_adjust_symtab (void)
1716
{
1717
  if (symbol_rootP == NULL
1718
      || S_GET_STORAGE_CLASS (symbol_rootP) != C_FILE)
1719
    c_dot_file_symbol ("fake", 0);
1720
}
1721
 
1722
void
1723
coff_frob_section (segT sec)
1724
{
1725
  segT strsec;
1726
  char *p;
1727
  fragS *fragp;
1728
  bfd_vma n_entries;
1729
 
1730
  /* The COFF back end in BFD requires that all section sizes be
1731
     rounded up to multiples of the corresponding section alignments,
1732
     supposedly because standard COFF has no other way of encoding alignment
1733
     for sections.  If your COFF flavor has a different way of encoding
1734
     section alignment, then skip this step, as TICOFF does.  */
1735
  bfd_vma size = bfd_get_section_size (sec);
1736
#if !defined(TICOFF)
1737
  bfd_vma align_power = (bfd_vma) sec->alignment_power + OCTETS_PER_BYTE_POWER;
1738
  bfd_vma mask = ((bfd_vma) 1 << align_power) - 1;
1739
 
1740
  if (size & mask)
1741
    {
1742
      bfd_vma new_size;
1743
      fragS *last;
1744
 
1745
      new_size = (size + mask) & ~mask;
1746
      bfd_set_section_size (stdoutput, sec, new_size);
1747
 
1748
      /* If the size had to be rounded up, add some padding in
1749
         the last non-empty frag.  */
1750
      fragp = seg_info (sec)->frchainP->frch_root;
1751
      last = seg_info (sec)->frchainP->frch_last;
1752
      while (fragp->fr_next != last)
1753
	fragp = fragp->fr_next;
1754
      last->fr_address = size;
1755
      fragp->fr_offset += new_size - size;
1756
    }
1757
#endif
1758
 
1759
  /* If the section size is non-zero, the section symbol needs an aux
1760
     entry associated with it, indicating the size.  We don't know
1761
     all the values yet; coff_frob_symbol will fill them in later.  */
1762
#ifndef TICOFF
1763
  if (size != 0
1764
      || sec == text_section
1765
      || sec == data_section
1766
      || sec == bss_section)
1767
#endif
1768
    {
1769
      symbolS *secsym = section_symbol (sec);
1770
      unsigned char sclass = C_STAT;
1771
 
1772
#ifdef OBJ_XCOFF
1773
      if (bfd_get_section_flags (stdoutput, sec) & SEC_DEBUGGING)
1774
        sclass = C_DWARF;
1775
#endif
1776
      S_SET_STORAGE_CLASS (secsym, sclass);
1777
      S_SET_NUMBER_AUXILIARY (secsym, 1);
1778
      SF_SET_STATICS (secsym);
1779
      SA_SET_SCN_SCNLEN (secsym, size);
1780
    }
1781
  /* FIXME: These should be in a "stabs.h" file, or maybe as.h.  */
1782
#ifndef STAB_SECTION_NAME
1783
#define STAB_SECTION_NAME ".stab"
1784
#endif
1785
#ifndef STAB_STRING_SECTION_NAME
1786
#define STAB_STRING_SECTION_NAME ".stabstr"
1787
#endif
1788
  if (! streq (STAB_STRING_SECTION_NAME, sec->name))
1789
    return;
1790
 
1791
  strsec = sec;
1792
  sec = subseg_get (STAB_SECTION_NAME, 0);
1793
  /* size is already rounded up, since other section will be listed first */
1794
  size = bfd_get_section_size (strsec);
1795
 
1796
  n_entries = bfd_get_section_size (sec) / 12 - 1;
1797
 
1798
  /* Find first non-empty frag.  It should be large enough.  */
1799
  fragp = seg_info (sec)->frchainP->frch_root;
1800
  while (fragp && fragp->fr_fix == 0)
1801
    fragp = fragp->fr_next;
1802
  gas_assert (fragp != 0 && fragp->fr_fix >= 12);
1803
 
1804
  /* Store the values.  */
1805
  p = fragp->fr_literal;
1806
  bfd_h_put_16 (stdoutput, n_entries, (bfd_byte *) p + 6);
1807
  bfd_h_put_32 (stdoutput, size, (bfd_byte *) p + 8);
1808
}
1809
 
1810
void
1811
obj_coff_init_stab_section (segT seg)
1812
{
1813
  char *file;
1814
  char *p;
1815
  char *stabstr_name;
1816
  unsigned int stroff;
1817
 
1818
  /* Make space for this first symbol.  */
1819
  p = frag_more (12);
1820
  /* Zero it out.  */
1821
  memset (p, 0, 12);
1822
  as_where (&file, (unsigned int *) NULL);
1823
  stabstr_name = xmalloc (strlen (seg->name) + 4);
1824
  strcpy (stabstr_name, seg->name);
1825
  strcat (stabstr_name, "str");
1826
  stroff = get_stab_string_offset (file, stabstr_name);
1827
  know (stroff == 1);
1828
  md_number_to_chars (p, stroff, 4);
1829
}
1830
 
1831
#ifdef DEBUG
1832
const char * s_get_name (symbolS *);
1833
 
1834
const char *
1835
s_get_name (symbolS *s)
1836
{
1837
  return ((s == NULL) ? "(NULL)" : S_GET_NAME (s));
1838
}
1839
 
1840
void symbol_dump (void);
1841
 
1842
void
1843
symbol_dump (void)
1844
{
1845
  symbolS *symbolP;
1846
 
1847
  for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next (symbolP))
1848
    printf (_("0x%lx: \"%s\" type = %ld, class = %d, segment = %d\n"),
1849
	    (unsigned long) symbolP,
1850
	    S_GET_NAME (symbolP),
1851
	    (long) S_GET_DATA_TYPE (symbolP),
1852
	    S_GET_STORAGE_CLASS (symbolP),
1853
	    (int) S_GET_SEGMENT (symbolP));
1854
}
1855
 
1856
#endif /* DEBUG */
1857
 
1858
const pseudo_typeS coff_pseudo_table[] =
1859
{
1860
  {"ABORT", s_abort, 0},
1861
  {"appline", obj_coff_ln, 1},
1862
  /* We accept the .bss directive for backward compatibility with
1863
     earlier versions of gas.  */
1864
  {"bss", obj_coff_bss, 0},
1865
#ifdef TE_PE
1866
  /* PE provides an enhanced version of .comm with alignment.  */
1867
  {"comm", obj_coff_comm, 0},
1868
#endif /* TE_PE */
1869
  {"def", obj_coff_def, 0},
1870
  {"dim", obj_coff_dim, 0},
1871
  {"endef", obj_coff_endef, 0},
1872
  {"ident", obj_coff_ident, 0},
1873
  {"line", obj_coff_line, 0},
1874
  {"ln", obj_coff_ln, 0},
1875
  {"scl", obj_coff_scl, 0},
1876
  {"sect", obj_coff_section, 0},
1877
  {"sect.s", obj_coff_section, 0},
1878
  {"section", obj_coff_section, 0},
1879
  {"section.s", obj_coff_section, 0},
1880
  /* FIXME: We ignore the MRI short attribute.  */
1881
  {"size", obj_coff_size, 0},
1882
  {"tag", obj_coff_tag, 0},
1883
  {"type", obj_coff_type, 0},
1884
  {"val", obj_coff_val, 0},
1885
  {"version", s_ignore, 0},
1886
  {"loc", obj_coff_loc, 0},
1887
  {"optim", s_ignore, 0},	/* For sun386i cc (?) */
1888
  {"weak", obj_coff_weak, 0},
1889
#if defined TC_TIC4X
1890
  /* The tic4x uses sdef instead of def.  */
1891
  {"sdef", obj_coff_def, 0},
1892
#endif
1893
#if defined(SEH_CMDS)
1894
  SEH_CMDS
1895
#endif
1896
  {NULL, NULL, 0}
1897
};
1898
 
1899
 
1900
/* Support for a COFF emulation.  */
1901
 
1902
static void
1903
coff_pop_insert (void)
1904
{
1905
  pop_insert (coff_pseudo_table);
1906
}
1907
 
1908
static int
1909
coff_separate_stab_sections (void)
1910
{
1911
  return 1;
1912
}
1913
 
1914
const struct format_ops coff_format_ops =
1915
{
1916
  bfd_target_coff_flavour,
1917
  0,	/* dfl_leading_underscore */
1918
  1,	/* emit_section_symbols */
1919
  0,    /* begin */
1920
  c_dot_file_symbol,
1921
  coff_frob_symbol,
1922
  0,	/* frob_file */
1923
  0,	/* frob_file_before_adjust */
1924
  0,	/* frob_file_before_fix */
1925
  coff_frob_file_after_relocs,
1926
  0,	/* s_get_size */
1927
  0,	/* s_set_size */
1928
  0,	/* s_get_align */
1929
  0,	/* s_set_align */
1930
  0,	/* s_get_other */
1931
  0,	/* s_set_other */
1932
  0,	/* s_get_desc */
1933
  0,	/* s_set_desc */
1934
  0,	/* s_get_type */
1935
  0,	/* s_set_type */
1936
  0,	/* copy_symbol_attributes */
1937
  0,	/* generate_asm_lineno */
1938
  0,	/* process_stab */
1939
  coff_separate_stab_sections,
1940
  obj_coff_init_stab_section,
1941
  0,	/* sec_sym_ok_for_reloc */
1942
  coff_pop_insert,
1943
  0,	/* ecoff_set_ext */
1944
  coff_obj_read_begin_hook,
1945
  coff_obj_symbol_new_hook,
1946
  coff_obj_symbol_clone_hook,
1947
  coff_adjust_symtab
1948
};