* config/obj-elf.c (obj_elf_init_stab_section): Align .stab
[platform/upstream/binutils.git] / gas / config / obj-elf.c
1 /* ELF object file format
2    Copyright (C) 1992, 1993 Free Software Foundation, Inc.
3
4    This file is part of GAS, the GNU Assembler.
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
8    published by the Free Software Foundation; either version 2,
9    or (at your option) any later version.
10
11    GAS is distributed in the hope that it will be useful, but
12    WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
14    the GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public
17    License along with GAS; see the file COPYING.  If not, write
18    to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20 #include "as.h"
21 #include "subsegs.h"
22 #include "obstack.h"
23
24 static int obj_elf_write_symbol_p PARAMS ((symbolS *sym));
25
26 static void obj_elf_line PARAMS ((int));
27 void obj_elf_version PARAMS ((int));
28 static void obj_elf_size PARAMS ((int));
29 static void obj_elf_type PARAMS ((int));
30 static void obj_elf_ident PARAMS ((int));
31 static void obj_elf_weak PARAMS ((int));
32 static void obj_elf_local PARAMS ((int));
33 static void obj_elf_common PARAMS ((int));
34 static void obj_elf_data PARAMS ((int));
35 static void obj_elf_text PARAMS ((int));
36
37 const pseudo_typeS obj_pseudo_table[] =
38 {
39   {"comm", obj_elf_common, 0},
40   {"ident", obj_elf_ident, 0},
41   {"local", obj_elf_local, 0},
42   {"previous", obj_elf_previous, 0},
43   {"section", obj_elf_section, 0},
44   {"size", obj_elf_size, 0},
45   {"type", obj_elf_type, 0},
46   {"version", obj_elf_version, 0},
47   {"weak", obj_elf_weak, 0},
48
49 /* These are used for stabs-in-elf configurations.  */
50   {"line", obj_elf_line, 0},
51
52   /* These are used for dwarf. */
53   {"2byte", cons, 2},
54   {"4byte", cons, 4},
55   {"8byte", cons, 8},
56
57   /* We need to trap the section changing calls to handle .previous.  */
58   {"data", obj_elf_data, 0},
59   {"text", obj_elf_text, 0},
60
61   {NULL}                        /* end sentinel */
62 };
63
64 #undef NO_RELOC
65 #include "aout/aout64.h"
66
67 void
68 elf_file_symbol (s)
69      char *s;
70 {
71   symbolS *sym;
72
73   sym = symbol_new (s, absolute_section, (valueT) 0, (struct frag *) 0);
74   sym->sy_frag = &zero_address_frag;
75   sym->bsym->flags |= BSF_FILE;
76
77   if (symbol_rootP != sym)
78     {
79       symbol_remove (sym, &symbol_rootP, &symbol_lastP);
80       symbol_insert (sym, symbol_rootP, &symbol_rootP, &symbol_lastP);
81 #ifdef DEBUG
82       verify_symbol_chain (symbol_rootP, symbol_lastP);
83 #endif
84     }
85 }
86
87 static void
88 obj_elf_common (ignore)
89      int ignore;
90 {
91   char *name;
92   char c;
93   char *p;
94   int temp, size;
95   symbolS *symbolP;
96   int have_align;
97
98   name = input_line_pointer;
99   c = get_symbol_end ();
100   /* just after name is now '\0' */
101   p = input_line_pointer;
102   *p = c;
103   SKIP_WHITESPACE ();
104   if (*input_line_pointer != ',')
105     {
106       as_bad ("Expected comma after symbol-name");
107       ignore_rest_of_line ();
108       return;
109     }
110   input_line_pointer++;         /* skip ',' */
111   if ((temp = get_absolute_expression ()) < 0)
112     {
113       as_bad (".COMMon length (%d.) <0! Ignored.", temp);
114       ignore_rest_of_line ();
115       return;
116     }
117   size = temp;
118   *p = 0;
119   symbolP = symbol_find_or_make (name);
120   *p = c;
121   if (S_IS_DEFINED (symbolP))
122     {
123       as_bad ("Ignoring attempt to re-define symbol");
124       ignore_rest_of_line ();
125       return;
126     }
127   if (S_GET_VALUE (symbolP) != 0)
128     {
129       if (S_GET_VALUE (symbolP) != size)
130         {
131           as_warn ("Length of .comm \"%s\" is already %ld. Not changed to %d.",
132                    S_GET_NAME (symbolP), (long) S_GET_VALUE (symbolP), size);
133         }
134     }
135   know (symbolP->sy_frag == &zero_address_frag);
136   if (*input_line_pointer != ',')
137     have_align = 0;
138   else
139     {
140       have_align = 1;
141       input_line_pointer++;
142       SKIP_WHITESPACE ();
143     }
144   if (! have_align || *input_line_pointer != '"')
145     {
146       if (! have_align)
147         temp = 0;
148       else
149         {
150           temp = get_absolute_expression ();
151           if (temp < 0)
152             {
153               temp = 0;
154               as_warn ("Common alignment negative; 0 assumed");
155             }
156         }
157       if (symbolP->local)
158         {
159           segT old_sec;
160           int old_subsec;
161           char *pfrag;
162           int align;
163
164         /* allocate_bss: */
165           old_sec = now_seg;
166           old_subsec = now_subseg;
167           align = temp;
168           record_alignment (bss_section, align);
169           subseg_set (bss_section, 0);
170           if (align)
171             frag_align (align, 0);
172           if (S_GET_SEGMENT (symbolP) == bss_section)
173             symbolP->sy_frag->fr_symbol = 0;
174           symbolP->sy_frag = frag_now;
175           pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP, size,
176                             (char *) 0);
177           *pfrag = 0;
178           S_SET_SEGMENT (symbolP, bss_section);
179           S_CLEAR_EXTERNAL (symbolP);
180           subseg_set (old_sec, old_subsec);
181         }
182       else
183         {
184         allocate_common:
185           S_SET_VALUE (symbolP, (valueT) size);
186           S_SET_EXTERNAL (symbolP);
187           /* should be common, but this is how gas does it for now */
188           S_SET_SEGMENT (symbolP, &bfd_und_section);
189         }
190     }
191   else
192     {
193       input_line_pointer++;
194       /* @@ Some use the dot, some don't.  Can we get some consistency??  */
195       if (*input_line_pointer == '.')
196         input_line_pointer++;
197       /* @@ Some say data, some say bss.  */
198       if (strncmp (input_line_pointer, "bss\"", 4)
199           && strncmp (input_line_pointer, "data\"", 5))
200         {
201           while (*--input_line_pointer != '"')
202             ;
203           input_line_pointer--;
204           goto bad_common_segment;
205         }
206       while (*input_line_pointer++ != '"')
207         ;
208       goto allocate_common;
209     }
210   demand_empty_rest_of_line ();
211   return;
212
213   {
214   bad_common_segment:
215     p = input_line_pointer;
216     while (*p && *p != '\n')
217       p++;
218     c = *p;
219     *p = '\0';
220     as_bad ("bad .common segment %s", input_line_pointer + 1);
221     *p = c;
222     input_line_pointer = p;
223     ignore_rest_of_line ();
224     return;
225   }
226 }
227
228 static void 
229 obj_elf_local (ignore)
230      int ignore;
231 {
232   char *name;
233   int c;
234   symbolS *symbolP;
235
236   do
237     {
238       name = input_line_pointer;
239       c = get_symbol_end ();
240       symbolP = symbol_find_or_make (name);
241       *input_line_pointer = c;
242       SKIP_WHITESPACE ();
243       S_CLEAR_EXTERNAL (symbolP);
244       symbolP->local = 1;
245       if (c == ',')
246         {
247           input_line_pointer++;
248           SKIP_WHITESPACE ();
249           if (*input_line_pointer == '\n')
250             c = '\n';
251         }
252     }
253   while (c == ',');
254   demand_empty_rest_of_line ();
255 }
256
257 static void 
258 obj_elf_weak (ignore)
259      int ignore;
260 {
261   char *name;
262   int c;
263   symbolS *symbolP;
264
265   do
266     {
267       name = input_line_pointer;
268       c = get_symbol_end ();
269       symbolP = symbol_find_or_make (name);
270       *input_line_pointer = c;
271       SKIP_WHITESPACE ();
272       S_SET_WEAK (symbolP);
273       symbolP->local = 1;
274       if (c == ',')
275         {
276           input_line_pointer++;
277           SKIP_WHITESPACE ();
278           if (*input_line_pointer == '\n')
279             c = '\n';
280         }
281     }
282   while (c == ',');
283   demand_empty_rest_of_line ();
284 }
285
286 static segT previous_section;
287 static int previous_subsection;
288
289 /* Handle the .section pseudo-op.  This code supports two different
290    syntaxes.  
291
292    The first is found on Solaris, and looks like
293        .section ".sec1",#alloc,#execinstr,#write
294    Here the names after '#' are the SHF_* flags to turn on for the
295    section.  I'm not sure how it determines the SHT_* type (BFD
296    doesn't really give us control over the type, anyhow).
297
298    The second format is found on UnixWare, and probably most SVR4
299    machines, and looks like
300        .section .sec1,"a",@progbits
301    The quoted string may contain any combination of a, w, x, and
302    represents the SHF_* flags to turn on for the section.  The string
303    beginning with '@' can be progbits or nobits.  There should be
304    other possibilities, but I don't know what they are.  In any case,
305    BFD doesn't really let us set the section type.  */
306
307 void
308 obj_elf_section (xxx)
309      int xxx;
310 {
311   char *string;
312   int new_sec;
313   segT sec;
314   flagword flags;
315
316   /* Get name of section.  */
317   SKIP_WHITESPACE ();
318   if (*input_line_pointer == '"')
319     {
320       string = demand_copy_C_string (&xxx);
321       if (string == NULL)
322         {
323           ignore_rest_of_line ();
324           return;
325         }
326     }
327   else
328     {
329       char *p = input_line_pointer;
330       char c;
331       while (0 == strchr ("\n\t,; ", *p))
332         p++;
333       if (p == input_line_pointer)
334         {
335           as_warn ("Missing section name");
336           ignore_rest_of_line ();
337           return;
338         }
339       c = *p;
340       *p = 0;
341       string = xmalloc ((unsigned long) (p - input_line_pointer + 1));
342       strcpy (string, input_line_pointer);
343       *p = c;
344       input_line_pointer = p;
345     }
346
347   /* Switch to the section, creating it if necessary.  */
348   previous_section = now_seg;
349   previous_subsection = now_subseg;
350
351   new_sec = bfd_get_section_by_name (stdoutput, string) == NULL;
352   sec = subseg_new (string, 0);
353
354   /* If this section already existed, we don't bother to change the
355      flag values.  */
356   if (! new_sec)
357     {
358       while (! is_end_of_line[(unsigned char) *input_line_pointer])
359         ++input_line_pointer;
360       ++input_line_pointer;
361       return;
362     }
363
364   SKIP_WHITESPACE ();
365   if (*input_line_pointer != ',')
366     {
367       /* No flags given.  Guess at some useful defaults.  */
368       if (strcmp (string, ".data") == 0
369           || strcmp (string, ".data1") == 0
370           || strcmp (string, ".sdata") == 0
371           || strcmp (string, ".rodata") == 0
372           || strcmp (string, ".rodata1") == 0)
373         flags = SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_RELOC | SEC_DATA;
374       else if (strcmp (string, ".text") == 0
375                || strcmp (string, ".init") == 0
376                || strcmp (string, ".fini") == 0)
377         flags = SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_RELOC | SEC_CODE;
378       else if (strcmp (string, ".bss") == 0
379                || strcmp (string, ".sbss") == 0)
380         flags = SEC_ALLOC;
381       else
382         flags = SEC_RELOC;
383     }
384   else
385     {
386       /* Skip the comma.  */
387       ++input_line_pointer;
388
389       SKIP_WHITESPACE ();
390       if (*input_line_pointer == '"')
391         {
392           /* Pick up a string with a combination of a, w, x.  */
393           flags = SEC_READONLY | SEC_RELOC;
394           ++input_line_pointer;
395           while (*input_line_pointer != '"')
396             {
397               switch (*input_line_pointer)
398                 {
399                 case 'a':
400                   flags |= SEC_ALLOC | SEC_LOAD;
401                   break;
402                 case 'w':
403                   flags &=~ SEC_READONLY;
404                   break;
405                 case 'x':
406                   flags |= SEC_CODE;
407                   break;
408                 default:
409                   as_warn ("Bad .section directive: want a,w,x in string");
410                   ignore_rest_of_line ();
411                   return;
412                 }
413               ++input_line_pointer;
414             }
415
416           /* Skip the closing quote.  */
417           ++input_line_pointer;
418
419           SKIP_WHITESPACE ();
420           if (*input_line_pointer == ',')
421             {
422               ++input_line_pointer;
423               SKIP_WHITESPACE ();
424               if (*input_line_pointer == '@')
425                 {
426                   ++input_line_pointer;
427                   if (strncmp (input_line_pointer, "progbits",
428                                sizeof "progbits" - 1) == 0)
429                     {
430                       flags |= SEC_ALLOC | SEC_LOAD;
431                       input_line_pointer += sizeof "progbits" - 1;
432                     }
433                   else if (strncmp (input_line_pointer, "nobits",
434                                     sizeof "nobits" - 1) == 0)
435                     {
436                       flags &=~ SEC_LOAD;
437                       input_line_pointer += sizeof "nobits" - 1;
438                     }
439                   else
440                     {
441                       as_warn ("Unrecognized section type");
442                       ignore_rest_of_line ();
443                     }
444                 }
445             }
446         }
447       else
448         {
449           flags = SEC_READONLY | SEC_RELOC;
450           do
451             {
452               SKIP_WHITESPACE ();
453               if (*input_line_pointer != '#')
454                 {
455                   as_warn ("Bad .section directive");
456                   ignore_rest_of_line ();
457                   return;
458                 }
459               ++input_line_pointer;
460               if (strncmp (input_line_pointer, "write",
461                            sizeof "write" - 1) == 0)
462                 {
463                   flags &=~ SEC_READONLY;
464                   input_line_pointer += sizeof "write" - 1;
465                 }
466               else if (strncmp (input_line_pointer, "alloc",
467                                 sizeof "alloc" - 1) == 0)
468                 {
469                   flags |= SEC_ALLOC | SEC_LOAD;
470                   input_line_pointer += sizeof "alloc" - 1;
471                 }
472               else if (strncmp (input_line_pointer, "execinstr",
473                                 sizeof "execinstr" - 1) == 0)
474                 {
475                   flags |= SEC_CODE;
476                   input_line_pointer += sizeof "execinstr" - 1;
477                 }
478               else
479                 {
480                   as_warn ("Unrecognized section attribute");
481                   ignore_rest_of_line ();
482                   return;
483                 }
484               SKIP_WHITESPACE ();
485             }
486           while (*input_line_pointer++ == ',');
487           --input_line_pointer;
488         }
489     }
490
491   bfd_set_section_flags (stdoutput, sec, flags);
492
493   demand_empty_rest_of_line ();
494 }
495
496 /* Change to the .data section.  */
497
498 static void
499 obj_elf_data (i)
500      int i;
501 {
502   previous_section = now_seg;
503   previous_subsection = now_subseg;
504   s_data (i);
505 }
506
507 /* Change to the .text section.  */
508
509 static void
510 obj_elf_text (i)
511      int i;
512 {
513   previous_section = now_seg;
514   previous_subsection = now_subseg;
515   s_text (i);
516 }
517
518 void
519 obj_elf_previous (ignore)
520      int ignore;
521 {
522   if (previous_section == 0)
523     {
524       as_bad (".previous without corresponding .section; ignored");
525       return;
526     }
527   subseg_set (previous_section, previous_subsection);
528   previous_section = 0;
529 }
530
531 static int
532 obj_elf_write_symbol_p (sym)
533      symbolS *sym;
534 {
535   /* If this is a local symbol, are there any relocations for which
536      need this symbol? */
537
538   /* To find this out, we examine all relocations in all bfd sections
539      that have relocations.  If there is one that references this
540      symbol, we need to keep this symbol.  In this case, we return a
541      true status.  In all other cases, we return a false status. */
542
543   if (S_IS_LOCAL (sym))
544     {
545       asymbol *bsym = sym->bsym;
546       bfd *abfd = bsym->the_bfd;
547       asection *bsec;
548
549       for (bsec = abfd->sections; bsec; bsec = bsec->next)
550         {
551           struct reloc_cache_entry **rlocs = bsec->orelocation;
552           int rcnt = bsec->reloc_count;
553
554           if (rlocs)
555             {
556               int i;
557
558               for (i = 0; i < rcnt; i++)
559                 if (rlocs[i]->sym_ptr_ptr
560                     && rlocs[i]->sym_ptr_ptr[0] == bsym)
561                   return 1;
562             }
563           else
564             {
565               /* No relocations for this section.  Check the seg_info
566                  structure to see if there are any fixups for this
567                  section. */
568               segment_info_type *seginfo = seg_info (bsec);
569               fixS *fixp;
570
571               for (fixp = seginfo->fix_root; fixp; fixp = fixp->fx_next)
572                 if ((fixp->fx_addsy && fixp->fx_addsy->bsym == bsym)
573                     || (fixp->fx_subsy && fixp->fx_subsy->bsym == bsym))
574                   return 1;
575             }
576         }
577     }
578   return 0;
579 }
580
581 int
582 obj_elf_write_symbol (sym)
583      symbolS *sym;
584 {
585   return /* obj_elf_write_symbol_p (sym) || */ !S_IS_LOCAL (sym);
586 }
587
588 int
589 obj_elf_frob_symbol (sym, punt)
590      symbolS *sym;
591      int *punt;
592 {
593 #if 0 /* ?? The return value is ignored.  Only the value of *punt is
594          relevant.  */
595   return obj_elf_write_symbol_p (sym);
596 #endif
597  /* FIXME: Just return 0 until is fixed.  */
598  return 0;
599 }
600
601 static void
602 obj_elf_line (ignore)
603      int ignore;
604 {
605   /* Assume delimiter is part of expression.  BSD4.2 as fails with
606      delightful bug, so we are not being incompatible here. */
607   new_logical_line ((char *) NULL, (int) (get_absolute_expression ()));
608   demand_empty_rest_of_line ();
609 }
610
611 void 
612 obj_read_begin_hook ()
613 {
614 }
615
616 void 
617 obj_symbol_new_hook (symbolP)
618      symbolS *symbolP;
619 {
620 #if 0 /* BFD already takes care of this */
621   elf32_symbol_type *esym = (elf32_symbol_type *) symbolP;
622
623   /* There is an Elf_Internal_Sym and an Elf_External_Sym.  For now,
624      just zero them out.  */
625
626   bzero ((char *) &esym->internal_elf_sym, sizeof (esym->internal_elf_sym));
627   bzero ((char *) &esym->native_elf_sym, sizeof (esym->native_elf_sym));
628   bzero ((char *) &esym->tc_data, sizeof (esym->tc_data));
629 #endif
630 }
631
632 void 
633 obj_elf_version (ignore)
634      int ignore;
635 {
636   char *name;
637   unsigned int c;
638   char ch;
639   char *p;
640   asection *seg = now_seg;
641   subsegT subseg = now_subseg;
642   Elf_Internal_Note i_note;
643   Elf_External_Note e_note;
644   asection *note_secp = (asection *) NULL;
645   int i, len;
646
647   SKIP_WHITESPACE ();
648   if (*input_line_pointer == '\"')
649     {
650       ++input_line_pointer;     /* -> 1st char of string. */
651       name = input_line_pointer;
652
653       while (is_a_char (c = next_char_of_string ()))
654         ;
655       c = *input_line_pointer;
656       *input_line_pointer = '\0';
657       *(input_line_pointer - 1) = '\0';
658       *input_line_pointer = c;
659
660       /* create the .note section */
661
662       note_secp = subseg_new (".note", 0);
663       bfd_set_section_flags (stdoutput,
664                              note_secp,
665                              SEC_HAS_CONTENTS | SEC_READONLY);
666
667       /* process the version string */
668
669       len = strlen (name);
670
671       i_note.namesz = ((len + 1) + 3) & ~3; /* round this to word boundary */
672       i_note.descsz = 0;        /* no description */
673       i_note.type = NT_VERSION;
674       p = frag_more (sizeof (e_note.namesz));
675       md_number_to_chars (p, (valueT) i_note.namesz, 4);
676       p = frag_more (sizeof (e_note.descsz));
677       md_number_to_chars (p, (valueT) i_note.descsz, 4);
678       p = frag_more (sizeof (e_note.type));
679       md_number_to_chars (p, (valueT) i_note.type, 4);
680
681       for (i = 0; i < len; i++)
682         {
683           ch = *(name + i);
684           {
685             FRAG_APPEND_1_CHAR (ch);
686           }
687         }
688       frag_align (2, 0);
689
690       subseg_set (seg, subseg);
691     }
692   else
693     {
694       as_bad ("Expected quoted string");
695     }
696   demand_empty_rest_of_line ();
697 }
698
699 static void
700 obj_elf_size (ignore)
701      int ignore;
702 {
703   char *name = input_line_pointer;
704   char c = get_symbol_end ();
705   char *p;
706   expressionS exp;
707   symbolS *sym;
708
709   p = input_line_pointer;
710   *p = c;
711   SKIP_WHITESPACE ();
712   if (*input_line_pointer != ',')
713     {
714       *p = 0;
715       as_bad ("expected comma after name `%s' in .size directive", name);
716       *p = c;
717       ignore_rest_of_line ();
718       return;
719     }
720   input_line_pointer++;
721   expression (&exp);
722   if (exp.X_op == O_absent)
723     {
724       as_bad ("missing expression in .size directive");
725       exp.X_op = O_constant;
726       exp.X_add_number = 0;
727     }
728   *p = 0;
729   sym = symbol_find_or_make (name);
730   *p = c;
731   if (exp.X_op == O_constant)
732     S_SET_SIZE (sym, exp.X_add_number);
733   else
734     {
735 #if 0
736       static int warned;
737       if (!warned)
738         {
739           as_tsktsk (".size expressions not yet supported, ignored");
740           warned++;
741         }
742 #endif
743     }
744   demand_empty_rest_of_line ();
745 }
746
747 static void
748 obj_elf_type (ignore)
749      int ignore;
750 {
751   char *name = input_line_pointer;
752   char c = get_symbol_end ();
753   char *p;
754   int type = 0;
755   symbolS *sym;
756
757   p = input_line_pointer;
758   *p = c;
759   SKIP_WHITESPACE ();
760   if (*input_line_pointer != ',')
761     {
762       as_bad ("expected comma after name in .type directive");
763     egress:
764       ignore_rest_of_line ();
765       return;
766     }
767   input_line_pointer++;
768   SKIP_WHITESPACE ();
769   if (*input_line_pointer != '#' && *input_line_pointer != '@')
770     {
771       as_bad ("expected `#' or `@' after comma in .type directive");
772       goto egress;
773     }
774   input_line_pointer++;
775   if (!strncmp ("function", input_line_pointer, sizeof ("function") - 1))
776     {
777       type = BSF_FUNCTION;
778       input_line_pointer += sizeof ("function") - 1;
779     }
780   else if (!strncmp ("object", input_line_pointer, sizeof ("object") - 1))
781     {
782       input_line_pointer += sizeof ("object") - 1;
783     }
784   else
785     {
786       as_bad ("unrecognized symbol type, ignored");
787       goto egress;
788     }
789   demand_empty_rest_of_line ();
790   *p = 0;
791   sym = symbol_find_or_make (name);
792   sym->bsym->flags |= type;
793 }
794
795 static void
796 obj_elf_ident (ignore)
797      int ignore;
798 {
799   static segT comment_section;
800   segT old_section = now_seg;
801   int old_subsection = now_subseg;
802
803   if (!comment_section)
804     {
805       char *p;
806       comment_section = subseg_new (".comment", 0);
807       bfd_set_section_flags (stdoutput, comment_section,
808                              SEC_READONLY | SEC_HAS_CONTENTS);
809       p = frag_more (1);
810       *p = 0;
811     }
812   else
813     subseg_set (comment_section, 0);
814   stringer (1);
815   subseg_set (old_section, old_subsection);
816 }
817
818 /* The first entry in a .stabs section is special.  */
819
820 void
821 obj_elf_init_stab_section (seg)
822      segT seg;
823 {
824   char *file;
825   char *p;
826   unsigned int stroff;
827
828   /* Force the section to align to a longword boundary.  Without this,
829      UnixWare ar crashes.  */
830   bfd_set_section_alignment (stdoutput, seg, 2);
831
832   p = frag_more (12);
833   as_where (&file, (unsigned int *) NULL);
834   stroff = get_stab_string_offset (file, segment_name (seg));
835   know (stroff == 1);
836   md_number_to_chars (p, stroff, 4);
837   seg_info (seg)->stabu.p = p;
838 }
839
840 /* Fill in the counts in the first entry in a .stabs section.  */
841
842 static void
843 adjust_stab_sections (abfd, sec, xxx)
844      bfd *abfd;
845      asection *sec;
846      PTR xxx;
847 {
848   char *name;
849   asection *strsec;
850   char *p;
851   int strsz, nsyms;
852
853   if (strncmp (".stab", sec->name, 5))
854     return;
855   if (!strcmp ("str", sec->name + strlen (sec->name) - 3))
856     return;
857
858   name = (char *) alloca (strlen (sec->name) + 4);
859   strcpy (name, sec->name);
860   strcat (name, "str");
861   strsec = bfd_get_section_by_name (abfd, name);
862   if (strsec)
863     strsz = bfd_section_size (abfd, strsec);
864   else
865     strsz = 0;
866   nsyms = bfd_section_size (abfd, sec) / 12 - 1;
867
868   p = seg_info (sec)->stabu.p;
869   assert (p != 0);
870
871   bfd_h_put_16 (abfd, (bfd_vma) nsyms, (bfd_byte *) p + 6);
872   bfd_h_put_32 (abfd, (bfd_vma) strsz, (bfd_byte *) p + 8);
873 }
874
875 void 
876 elf_frob_file ()
877 {
878   bfd_map_over_sections (stdoutput, adjust_stab_sections, (PTR) 0);
879
880 #ifdef elf_tc_symbol
881   {
882     int i;
883
884     for (i = 0; i < stdoutput->symcount; i++)
885       elf_tc_symbol (stdoutput, (PTR) (stdoutput->outsymbols[i]),
886                      i + 1);
887   }
888 #endif
889
890 #ifdef elf_tc_final_processing
891   elf_tc_final_processing ();
892 #endif
893
894   /* Finally, we must make any target-specific sections. */
895
896 #ifdef elf_tc_make_sections
897   elf_tc_make_sections (stdoutput);
898 #endif
899 }