7d99c9a97a75d46609d892d9754425c8275728a3
[binutils-gdb.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 "aout/stab_gnu.h"
23 #include "obstack.h"
24
25 static void obj_elf_stab PARAMS ((int what));
26 static void obj_elf_xstab PARAMS ((int what));
27 static void obj_elf_line PARAMS ((void));
28 void obj_elf_desc PARAMS ((void));
29 void obj_elf_version PARAMS ((void));
30 static void obj_elf_section PARAMS ((int));
31 static void obj_elf_size PARAMS ((void));
32 static void obj_elf_type PARAMS ((void));
33 static void obj_elf_ident PARAMS ((void));
34 static void obj_elf_previous PARAMS ((void));
35
36 const pseudo_typeS obj_pseudo_table[] =
37 {
38 {"ident", obj_elf_ident, 0},
39 {"previous", obj_elf_previous, 0},
40 {"section", obj_elf_section, 0},
41 {"size", obj_elf_size, 0},
42 {"type", obj_elf_type, 0},
43 {"version", obj_elf_version, 0},
44
45 /* These are used for stabs-in-elf configurations. */
46 {"desc", obj_elf_desc, 0},
47 {"line", obj_elf_line, 0},
48 {"stabd", obj_elf_stab, 'd'},
49 {"stabn", obj_elf_stab, 'n'},
50 {"stabs", obj_elf_stab, 's'},
51 /* This is used on Solaris 2.x on SPARC, but not supported yet. */
52 {"xstabs", obj_elf_xstab, 's'},
53
54 /* These are used for dwarf. */
55 {"2byte", cons, 2},
56 {"4byte", cons, 4},
57
58 {NULL} /* end sentinel */
59 };
60
61 #include "aout/aout64.h"
62
63 void
64 elf_file_symbol (s)
65 char *s;
66 {
67 symbolS *sym;
68
69 sym = symbol_new (s, absolute_section, (valueT) 0, (struct frag *) 0);
70 sym->sy_frag = &zero_address_frag;
71 sym->bsym->flags |= BSF_FILE;
72
73 if (symbol_rootP != sym)
74 {
75 symbol_remove (sym, &symbol_rootP, &symbol_lastP);
76 symbol_insert (sym, symbol_rootP, &symbol_rootP, &symbol_lastP);
77 #ifdef DEBUG
78 verify_symbol_chain (symbol_rootP, symbol_lastP);
79 #endif
80 }
81 }
82
83 static segT previous_section;
84 static int previous_subsection;
85
86 static void
87 obj_elf_section (xxx)
88 int xxx;
89 {
90 char *string;
91 asection *sec;
92
93 /* Initialize this with inclusive-or of all flags that can be cleared
94 by attributes, but not set by them. Also include flags that won't
95 get set properly in the assembler, but which the user/compiler
96 shouldn't be expected to set. */
97 flagword flags = SEC_READONLY | SEC_ALLOC | SEC_RELOC;
98 /* Initialize this with the default flags to be used if none are
99 specified. */
100 flagword default_flags = 0;
101
102 SKIP_WHITESPACE ();
103 if (*input_line_pointer == '"')
104 string = demand_copy_C_string (&xxx);
105 else
106 {
107 char *p = input_line_pointer;
108 char c;
109 while (0 == strchr ("\n\t,; ", *p))
110 p++;
111 c = *p;
112 *p = 0;
113 string = xmalloc (p - input_line_pointer + 1);
114 strcpy (string, input_line_pointer);
115 *p = c;
116 input_line_pointer = p;
117 }
118 if (!strcmp (string, ".rodata"))
119 default_flags = SEC_ALLOC | SEC_READONLY | SEC_RELOC;
120 SKIP_WHITESPACE ();
121 if (*input_line_pointer != ',')
122 flags = default_flags;
123 while (*input_line_pointer == ',')
124 {
125 flagword bit;
126 int len, inv;
127 char *p, oldp;
128
129 input_line_pointer++;
130 if (*input_line_pointer != '#' && *input_line_pointer != '@')
131 {
132 as_bad ("unrecognized syntax in .section command");
133 ignore_rest_of_line ();
134 break;
135 }
136 input_line_pointer++;
137
138 #define CHECK(X,BIT,NEG) \
139 if (!strncmp(X,input_line_pointer,len = sizeof(X) - 1)) { \
140 bit = BIT; inv = NEG; goto match; }
141
142 CHECK ("write", SEC_READONLY, 1);
143 CHECK ("alloc", SEC_ALLOC, 0);
144 CHECK ("execinstr", SEC_CODE, 1);
145 #undef CHECK
146
147 p = input_line_pointer;
148 while (!is_end_of_line[*p] && *p != 0 && *p != ',')
149 p++;
150 *p = 0;
151 oldp = *p;
152 as_bad ("unrecognized section attribute `%s' ignored",
153 input_line_pointer);
154 *p = oldp;
155 continue;
156
157 match:
158 if (inv)
159 flags &= ~bit;
160 else
161 flags |= bit;
162 input_line_pointer += len;
163 }
164 demand_empty_rest_of_line ();
165
166 /* If the C string wasn't valid, `string' could be null. */
167 if (!string)
168 return;
169
170 sec = bfd_get_section_by_name (stdoutput, string);
171 if (sec == 0)
172 {
173 sec = subseg_new (string, 0);
174 bfd_set_section_flags (stdoutput, sec, flags);
175 sec->output_section = sec;
176 }
177 previous_section = now_seg;
178 previous_subsection = now_subseg;
179 subseg_set (sec, 0);
180 }
181
182 static void
183 obj_elf_previous ()
184 {
185 if (previous_section == 0)
186 {
187 as_bad (".previous without corresponding .section; ignored");
188 return;
189 }
190 subseg_set (previous_section, previous_subsection);
191 previous_section = 0;
192 }
193
194 int
195 obj_elf_write_symbol_p (sym)
196 symbolS *sym;
197 {
198 /* If this is a local symbol, are there any relocations for which
199 need this symbol? */
200
201 /* To find this out, we examine all relocations in all bfd sections
202 that have relocations. If there is one that references this
203 symbol, we need to keep this symbol. In this case, we return a
204 true status. In all other cases, we return a false status. */
205
206 if (S_IS_LOCAL (sym))
207 {
208 asymbol *bsym = sym->bsym;
209 bfd *abfd = bsym->the_bfd;
210 asection *bsec;
211
212 for (bsec = abfd->sections; bsec; bsec = bsec->next)
213 {
214 struct reloc_cache_entry **rlocs = bsec->orelocation;
215 int rcnt = bsec->reloc_count;
216
217 if (rlocs)
218 {
219 int i;
220
221 for (i = 0; i < rcnt; i++)
222 if (rlocs[i]->sym_ptr_ptr
223 && rlocs[i]->sym_ptr_ptr[0] == bsym)
224 return 1;
225 }
226 else
227 {
228 /* No relocations for this section. Check the seg_info
229 structure to see if there are any fixups for this
230 section. */
231 segment_info_type *seginfo = seg_info (bsec);
232 fixS *fixp;
233
234 for (fixp = seginfo->fix_root; fixp; fixp = fixp->fx_next)
235 if ((fixp->fx_addsy && fixp->fx_addsy->bsym == bsym)
236 || (fixp->fx_subsy && fixp->fx_subsy->bsym == bsym))
237 return 1;
238 }
239 }
240 }
241 return 0;
242 }
243
244 int
245 obj_elf_write_symbol (sym)
246 symbolS *sym;
247 {
248 return /* obj_elf_write_symbol_p (sym) || */ !S_IS_LOCAL (sym);
249 }
250
251 int
252 obj_elf_frob_symbol (sym, punt)
253 symbolS *sym;
254 int *punt;
255 {
256 return obj_elf_write_symbol_p (sym);
257 }
258
259 static void
260 obj_elf_line ()
261 {
262 /* Assume delimiter is part of expression. BSD4.2 as fails with
263 delightful bug, so we are not being incompatible here. */
264 new_logical_line ((char *) NULL, (int) (get_absolute_expression ()));
265 demand_empty_rest_of_line ();
266 }
267
268 /*
269 * stab()
270 *
271 * Handle .stabX directives, which used to be open-coded.
272 * So much creeping featurism overloaded the semantics that we decided
273 * to put all .stabX thinking in one place. Here.
274 *
275 * We try to make any .stabX directive legal. Other people's AS will often
276 * do assembly-time consistency checks: eg assigning meaning to n_type bits
277 * and "protecting" you from setting them to certain values. (They also zero
278 * certain bits before emitting symbols. Tut tut.)
279 *
280 * If an expression is not absolute we either gripe or use the relocation
281 * information. Other people's assemblers silently forget information they
282 * don't need and invent information they need that you didn't supply.
283 *
284 * .stabX directives always make a symbol table entry. It may be junk if
285 * the rest of your .stabX directive is malformed.
286 */
287
288 /*
289 * elf_stab_symbol_string()
290 *
291 * Build a string dictionary entry for a .stabX symbol.
292 * The symbol is added to the .stabstr section.
293 *
294 */
295
296 static unsigned int
297 elf_stab_symbol_string (string, secname)
298 char *string, *secname;
299 {
300 asection *save_seg;
301 asection *seg;
302 subsegT save_subseg;
303 unsigned int length;
304 unsigned int old_gdb_string_index;
305 char *clengthP;
306 int i;
307 char c;
308 /* @@FIXME -- there should be no static data here!
309 This also has the effect of making all stab string tables large enough
310 to contain all the contents written to any of them. This only matters
311 with the Solaris native compiler for the moment, but it should be fixed
312 anyways. */
313 static unsigned int gdb_string_index = 0;
314
315 old_gdb_string_index = 0;
316 length = strlen (string);
317 clengthP = (char *) &length;
318 if (length > 0)
319 { /* Ordinary case. */
320 save_seg = now_seg;
321 save_subseg = now_subseg;
322
323 /* Create the stab sections, if they are not already created. */
324 {
325 char *newsecname = xmalloc (strlen (secname) + 4);
326 strcpy (newsecname, secname);
327 strcat (newsecname, "str");
328 seg = bfd_get_section_by_name (stdoutput, newsecname);
329 if (seg == 0)
330 {
331 seg = bfd_make_section_old_way (stdoutput, newsecname);
332 bfd_set_section_flags (stdoutput, seg, SEC_READONLY | SEC_ALLOC);
333 }
334 /* free (newsecname);*/
335 }
336 subseg_new ((char *) seg->name, save_subseg);
337 old_gdb_string_index = gdb_string_index;
338 i = 0;
339 while ((c = *string++))
340 {
341 i++;
342 gdb_string_index++;
343 FRAG_APPEND_1_CHAR (c);
344 }
345 {
346 FRAG_APPEND_1_CHAR ((char) 0);
347 i++;
348 gdb_string_index++;
349 }
350 while (i % 4 != 0)
351 {
352 FRAG_APPEND_1_CHAR ((char) 0);
353 i++;
354 gdb_string_index++;
355 }
356 subseg_new ((char *) save_seg->name, save_subseg);
357 }
358
359 return old_gdb_string_index;
360 }
361
362 static void
363 DEFUN (elf_stab_symbol, (symbolP, stab_type),
364 symbolS *symbolP AND
365 int stab_type)
366 {
367 char *toP;
368
369 toP = frag_more (8);
370 /* the string index portion of the stab */
371 md_number_to_chars (toP, (valueT) symbolP->sy_name_offset, 4);
372 md_number_to_chars (toP + 4, (valueT) S_GET_TYPE (symbolP), 1);
373 md_number_to_chars (toP + 5, (valueT) S_GET_OTHER (symbolP), 1);
374 md_number_to_chars (toP + 6, (valueT) S_GET_DESC (symbolP), 2);
375 /* The n_value field doesn't get written here, it gets done below. It
376 may be an expression needing relocating. */
377 }
378
379 static void
380 obj_elf_stab_generic (what, secname)
381 int what;
382 char *secname;
383 {
384 extern int listing;
385
386 symbolS *symbolP = 0;
387 char *string;
388 int saved_type = 0;
389 int length;
390 int goof = 0;
391 long longint;
392 asection *saved_seg = now_seg;
393 asection *seg;
394 subsegT subseg = now_subseg;
395
396 #if 1
397 /* This function doesn't work yet.
398
399 Actually, this function is okay, but some finalizations are needed
400 before writing the object file; that's not done yet, and the Solaris
401 linker chokes without it.
402
403 In any case, this should effectively disable it for now. */
404 if (what == 's')
405 demand_copy_C_string (&length);
406 s_ignore (69);
407 return;
408 #endif
409
410 seg = bfd_get_section_by_name (stdoutput, secname);
411 if (seg == 0)
412 {
413 seg = subseg_new (secname, 0);
414 bfd_set_section_flags (stdoutput, seg,
415 SEC_READONLY | SEC_ALLOC | SEC_RELOC);
416 subseg_set (saved_seg, subseg);
417 }
418
419 /*
420 * Enter with input_line_pointer pointing past .stabX and any following
421 * whitespace.
422 */
423 if (what == 's')
424 {
425 string = demand_copy_C_string (&length);
426 SKIP_WHITESPACE ();
427 if (*input_line_pointer == ',')
428 input_line_pointer++;
429 else
430 {
431 as_bad ("I need a comma after symbol's name");
432 goof = 1;
433 }
434 }
435 else
436 string = "";
437
438 /*
439 * Input_line_pointer->after ','. String->symbol name.
440 */
441 if (!goof)
442 {
443 symbolP = symbol_new (string, &bfd_und_section, (valueT) 0, (struct frag *) 0);
444
445 /* enter the string in the .stab string table (section .stabstr) */
446 symbolP->sy_name_offset = elf_stab_symbol_string (string, secname);
447
448 switch (what)
449 {
450 case 'd':
451 S_SET_NAME (symbolP, NULL); /* .stabd feature. */
452 S_SET_VALUE (symbolP,
453 (valueT) ((char*) obstack_next_free (&frags) - frag_now->fr_literal));
454 S_SET_SEGMENT (symbolP, now_seg);
455 symbolP->sy_frag = frag_now;
456 break;
457
458 case 'n':
459 symbolP->sy_frag = &zero_address_frag;
460 break;
461
462 case 's':
463 symbolP->sy_frag = &zero_address_frag;
464 break;
465
466 default:
467 BAD_CASE (what);
468 break;
469 }
470
471 if (get_absolute_expression_and_terminator (&longint) == ',')
472 {
473 saved_type = longint;
474 S_SET_TYPE (symbolP, saved_type);
475 }
476 else
477 {
478 as_bad ("I want a comma after the n_type expression");
479 goof = 1;
480 input_line_pointer--; /* Backup over a non-',' char. */
481 }
482 }
483
484 if (!goof)
485 {
486 if (get_absolute_expression_and_terminator (&longint) == ',')
487 S_SET_OTHER (symbolP, longint);
488 else
489 {
490 as_bad ("I want a comma after the n_other expression");
491 goof = 1;
492 input_line_pointer--; /* Backup over a non-',' char. */
493 }
494 }
495
496 if (!goof)
497 {
498 S_SET_DESC (symbolP, get_absolute_expression ());
499 if (what == 's' || what == 'n')
500 {
501 if (*input_line_pointer != ',')
502 {
503 as_bad ("I want a comma after the n_desc expression");
504 goof = 1;
505 }
506 else
507 {
508 input_line_pointer++;
509 }
510 }
511 }
512
513 if (!goof)
514 {
515 subseg_new ((char *) seg->name, subseg);
516
517 /* Emit the stab symbol. */
518 elf_stab_symbol (symbolP, what);
519
520 if (what == 's' || what == 'n')
521 {
522 cons (4);
523 input_line_pointer--;
524 }
525 else
526 {
527 char *p = frag_more (4);
528 md_number_to_chars (p, 0, 0);
529 }
530 subseg_new ((char *) saved_seg->name, subseg);
531
532 if ((what == 's' || what == 'n')
533 && symbolP->sy_value.X_op == O_constant)
534 {
535 /* symbol is not needed in the regular symbol table */
536 symbol_remove (symbolP, &symbol_rootP, &symbol_lastP);
537 }
538
539 }
540
541 #ifndef NO_LISTING
542 if (listing && !goof)
543 switch (S_GET_TYPE (symbolP))
544 {
545 case N_SLINE:
546 listing_source_line (S_GET_DESC (symbolP));
547 break;
548 case N_SO:
549 case N_SOL:
550 listing_source_file (string);
551 break;
552 }
553 #endif
554
555 if (goof)
556 ignore_rest_of_line ();
557 else
558 demand_empty_rest_of_line ();
559 }
560
561 static void
562 obj_elf_stab (what)
563 int what;
564 {
565 obj_elf_stab_generic (what, ".stab");
566 }
567
568 static void
569 obj_elf_xstab (what)
570 int what;
571 {
572 int length;
573 char *secname;
574
575 secname = demand_copy_C_string (&length);
576 SKIP_WHITESPACE ();
577 if (*input_line_pointer == ',')
578 input_line_pointer++;
579 else
580 {
581 as_bad ("comma missing in .xstabs");
582 ignore_rest_of_line ();
583 return;
584 }
585 obj_elf_stab_generic (what, secname);
586 }
587
588 void
589 obj_elf_desc ()
590 {
591 char *name;
592 char c;
593 char *p;
594 symbolS *symbolP;
595 int temp;
596
597 /* Frob invented at RMS' request. Set the n_desc of a symbol. */
598 name = input_line_pointer;
599 c = get_symbol_end ();
600 p = input_line_pointer;
601 *p = c;
602 SKIP_WHITESPACE ();
603 if (*input_line_pointer != ',')
604 {
605 *p = 0;
606 as_bad ("Expected comma after name \"%s\"", name);
607 *p = c;
608 ignore_rest_of_line ();
609 }
610 else
611 {
612 input_line_pointer++;
613 temp = get_absolute_expression ();
614 *p = 0;
615 symbolP = symbol_find_or_make (name);
616 *p = c;
617 S_SET_DESC (symbolP, temp);
618 }
619 demand_empty_rest_of_line ();
620 } /* obj_elf_desc() */
621
622 void
623 obj_read_begin_hook ()
624 {
625 }
626
627 void
628 obj_symbol_new_hook (symbolP)
629 symbolS *symbolP;
630 {
631 #if 0 /* BFD already takes care of this */
632 elf32_symbol_type *esym = (elf32_symbol_type *) symbolP;
633
634 /* There is an Elf_Internal_Sym and an Elf_External_Sym. For now,
635 just zero them out. */
636
637 bzero ((char *) &esym->internal_elf_sym, sizeof (esym->internal_elf_sym));
638 bzero ((char *) &esym->native_elf_sym, sizeof (esym->native_elf_sym));
639 bzero ((char *) &esym->tc_data, sizeof (esym->tc_data));
640 #endif
641 }
642
643 void
644 obj_elf_version ()
645 {
646 char *name;
647 unsigned int c;
648 char ch;
649 char *p;
650 asection *seg = now_seg;
651 subsegT subseg = now_subseg;
652 Elf_Internal_Note i_note;
653 Elf_External_Note e_note;
654 asection *note_secp = (asection *) NULL;
655 int i, len;
656
657 SKIP_WHITESPACE ();
658 if (*input_line_pointer == '\"')
659 {
660 ++input_line_pointer; /* -> 1st char of string. */
661 name = input_line_pointer;
662
663 while (is_a_char (c = next_char_of_string ()))
664 ;
665 c = *input_line_pointer;
666 *input_line_pointer = '\0';
667 *(input_line_pointer - 1) = '\0';
668 *input_line_pointer = c;
669
670 /* create the .note section if this is the first version string */
671
672 note_secp = bfd_get_section_by_name (stdoutput, ".note");
673 if (note_secp == (asection *) NULL)
674 {
675 note_secp = bfd_make_section_old_way (stdoutput, ".note");
676 bfd_set_section_flags (stdoutput,
677 note_secp,
678 SEC_LOAD | SEC_ALLOC | SEC_HAS_CONTENTS);
679 }
680
681 /* process the version string */
682
683 subseg_new ((char *) note_secp->name, 0);
684 len = strlen (name);
685
686 i_note.namesz = ((len + 1) + 3) & ~3; /* round this to word boundary */
687 i_note.descsz = 0; /* no description */
688 i_note.type = NT_VERSION;
689 p = frag_more (sizeof (e_note.namesz));
690 md_number_to_chars (p, (valueT) i_note.namesz, 4);
691 p = frag_more (sizeof (e_note.descsz));
692 md_number_to_chars (p, (valueT) i_note.descsz, 4);
693 p = frag_more (sizeof (e_note.type));
694 md_number_to_chars (p, (valueT) i_note.type, 4);
695
696 for (i = 0; i < len; i++)
697 {
698 ch = *(name + i);
699 {
700 FRAG_APPEND_1_CHAR (ch);
701 }
702 }
703 frag_align (2, 0);
704
705 subseg_new ((char *) seg->name, subseg);
706 }
707 else
708 {
709 as_bad ("Expected \"-ed string");
710 }
711 demand_empty_rest_of_line ();
712 }
713
714 static void
715 obj_elf_size ()
716 {
717 char *name = input_line_pointer;
718 char c = get_symbol_end ();
719 char *p;
720 expressionS exp;
721 symbolS *sym;
722
723 p = input_line_pointer;
724 *p = c;
725 SKIP_WHITESPACE ();
726 if (*input_line_pointer != ',')
727 {
728 *p = 0;
729 as_bad ("expected comma after name `%s' in .size directive", name);
730 *p = c;
731 ignore_rest_of_line ();
732 return;
733 }
734 input_line_pointer++;
735 expression (&exp);
736 if (exp.X_op == O_absent)
737 {
738 as_bad ("missing expression in .size directive");
739 exp.X_op = O_constant;
740 exp.X_add_number = 0;
741 }
742 *p = 0;
743 sym = symbol_find_or_make (name);
744 *p = c;
745 if (exp.X_op == O_constant)
746 S_SET_SIZE (sym, exp.X_add_number);
747 else
748 {
749 #if 0
750 static int warned;
751 if (!warned)
752 {
753 as_tsktsk (".size expressions not yet supported, ignored");
754 warned++;
755 }
756 #endif
757 }
758 demand_empty_rest_of_line ();
759 }
760
761 static void
762 obj_elf_type ()
763 {
764 char *name = input_line_pointer;
765 char c = get_symbol_end ();
766 char *p;
767 int type = 0;
768 symbolS *sym;
769
770 p = input_line_pointer;
771 *p = c;
772 SKIP_WHITESPACE ();
773 if (*input_line_pointer != ',')
774 {
775 as_bad ("expected comma after name in .type directive");
776 egress:
777 ignore_rest_of_line ();
778 return;
779 }
780 input_line_pointer++;
781 SKIP_WHITESPACE ();
782 if (*input_line_pointer != '#')
783 {
784 as_bad ("expected `#' after comma in .type directive");
785 goto egress;
786 }
787 input_line_pointer++;
788 if (!strncmp ("function", input_line_pointer, sizeof ("function") - 1))
789 {
790 type = BSF_FUNCTION;
791 input_line_pointer += sizeof ("function") - 1;
792 }
793 else if (!strncmp ("object", input_line_pointer, sizeof ("object") - 1))
794 {
795 input_line_pointer += sizeof ("object") - 1;
796 }
797 else
798 {
799 as_bad ("unrecognized symbol type, ignored");
800 goto egress;
801 }
802 demand_empty_rest_of_line ();
803 *p = 0;
804 sym = symbol_find_or_make (name);
805 sym->bsym->flags |= type;
806 }
807
808 static void
809 obj_elf_ident ()
810 {
811 static segT comment_section;
812 segT old_section = now_seg;
813 int old_subsection = now_subseg;
814
815 if (!comment_section)
816 {
817 char *p;
818 comment_section = subseg_new (".comment", 0);
819 bfd_set_section_flags (stdoutput, comment_section, SEC_HAS_CONTENTS);
820 p = frag_more (1);
821 *p = 0;
822 }
823 else
824 subseg_set (comment_section, 0);
825 stringer (1);
826 subseg_set (old_section, old_subsection);
827 }
828
829 void
830 elf_frob_file ()
831 {
832 #ifdef elf_tc_symbol
833 int i;
834
835 for (i = 0; i < stdoutput->symcount; i++)
836 elf_tc_symbol (stdoutput, (elf_symbol_type *) (stdoutput->outsymbols[i]), i + 1);
837 #endif
838 #ifdef elf_tc_final_processing
839 elf_tc_final_processing_hook ();
840 #endif
841
842 /* Finally, we must make any target-specific sections. */
843
844 #ifdef elf_tc_make_sections
845 elf_tc_make_sections (stdoutput, NULL);
846 #endif
847 }