]> Git Repo - binutils.git/blob - ld/ldsym.c
* Makefile.in (ldexp.o, ldctor.o, ldlang.o, ldmain.o, ldwrite.o, lexsup.o,
[binutils.git] / ld / ldsym.c
1 /* All symbol handling for the linker
2    Copyright (C) 1991 Free Software Foundation, Inc.
3    Written by Steve Chamberlain [email protected]
4  
5 This file is part of GLD, the Gnu Linker.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
20
21 /* 
22    We keep a hash table of global symbols. Each entry in a hash table
23    is called an ldsym_type. Each has three chains; a pointer to a
24    chain of definitions for the symbol (hopefully one long), a pointer
25    to a chain of references to the symbol, and a pointer to a chain of
26    common symbols. Each pointer points into the canonical symbol table
27    provided by bfd, each one of which points to an asymbol. During
28    linkage, the linker uses the udata field to point to the next entry
29    in a canonical table....
30
31
32    ld_sym
33                         |          |
34    +----------+         +----------+
35    | defs     |      a canonical symbol table
36    +----------+         +----------+
37    | refs     | ----->  | one entry|  -----> asymbol
38    +----------+         +----------+       |         |
39    | coms     |         |          |       +---------+
40    +----------+         +----------+       | udata   |-----> another canonical symbol
41                                            +---------+                               
42
43
44
45    It is very simple to make all the symbol pointers point to the same
46    definition - just run down the chain and make the asymbols pointers
47    within the canonical table point to the asymbol attacthed to the
48    definition of the symbol.
49
50 */
51
52 #include "bfd.h"
53 #include "sysdep.h"
54
55 #include "ld.h"
56 #include "ldsym.h"
57 #include "ldmisc.h"
58 #include "ldlang.h"
59 /* IMPORT */
60
61 extern bfd *output_bfd;
62 extern strip_symbols_type strip_symbols;
63 extern discard_locals_type discard_locals;
64 /* Head and tail of global symbol table chronological list */
65
66 ldsym_type *symbol_head = (ldsym_type *)NULL;
67 ldsym_type **symbol_tail_ptr = &symbol_head;
68 CONST char *keepsyms_file;
69 int kept_syms;
70
71 extern ld_config_type config;
72
73 struct obstack global_sym_obstack;
74 #define obstack_chunk_alloc ldmalloc
75 #define obstack_chunk_free  free
76
77 /*
78   incremented for each symbol in the ldsym_type table
79   no matter what flavour it is 
80 */
81 unsigned int global_symbol_count;
82
83 /* IMPORTS */
84
85 extern boolean option_longmap ;
86
87 /* LOCALS */
88 #define TABSIZE 1009
89 static ldsym_type *global_symbol_hash_table[TABSIZE];
90
91 /* Compute the hash code for symbol name KEY.  */
92 static 
93 #ifdef __GNUC__
94 __inline
95 #endif
96
97 int
98 DEFUN(hash_string,(key),
99       CONST char *key)
100 {
101   register CONST char *cp;
102   register int k;
103
104   cp = key;
105   k = 0;
106   while (*cp)
107     k = (((k << 1) + (k >> 14)) ^ (*cp++)) & 0x3fff;
108
109   return k;
110 }
111
112 static
113 #ifdef __GNUC__
114 __inline
115 #endif ldsym_type *bp;
116 ldsym_type *
117 DEFUN(search,(key,hashval) ,
118       CONST char *key AND
119       int hashval)
120 {
121   ldsym_type *bp;                                  
122   for (bp = global_symbol_hash_table[hashval]; bp; bp = bp->link)
123     if (! strcmp (key, bp->name)) {
124       if (bp->flags & SYM_INDIRECT) {   
125         /* Use the symbol we're aliased to instead */
126         return (ldsym_type *)(bp->sdefs_chain);
127       }
128       return bp;
129     }
130   return 0;
131 }
132
133
134 /* Get the symbol table entry for the global symbol named KEY.
135    Create one if there is none.  */
136 ldsym_type *
137 DEFUN(ldsym_get,(key),
138       CONST     char *key)
139 {
140   register int hashval;
141   register ldsym_type *bp;
142
143   /* Determine the proper bucket.  */
144
145   hashval = hash_string (key) % TABSIZE;
146
147   /* Search the bucket.  */
148   bp = search(key, hashval);
149   if(bp) {
150     return bp;
151   }
152
153   /* Nothing was found; create a new symbol table entry.  */
154
155   bp = (ldsym_type *) obstack_alloc (&global_sym_obstack, (bfd_size_type)(sizeof (ldsym_type)));
156   bp->srefs_chain = (asymbol **)NULL;
157   bp->sdefs_chain = (asymbol **)NULL;
158   bp->scoms_chain = (asymbol **)NULL;
159   bp->name = obstack_copy(&global_sym_obstack,  key, strlen(key)+1);
160   bp->flags = 0;
161   /* Add the entry to the bucket.  */
162
163   bp->link = global_symbol_hash_table[hashval];
164   global_symbol_hash_table[hashval] = bp;
165
166   /* Keep the chronological list up to date too */
167   *symbol_tail_ptr = bp;
168   symbol_tail_ptr = &bp->next;
169   bp->next = 0;
170   global_symbol_count++;
171
172   return bp;
173 }
174
175 /* Like `ldsym_get' but return 0 if the symbol is not already known.  */
176
177 ldsym_type *
178 DEFUN(ldsym_get_soft,(key),
179       CONST char *key)
180 {
181   register int hashval;
182   /* Determine which bucket.  */
183
184   hashval = hash_string (key) % TABSIZE;
185
186   /* Search the bucket.  */
187   return search(key, hashval);
188 }
189
190 static asymbol **
191 process_keepsyms (table, size)
192      asymbol ** table;
193      int size;
194 {
195   struct obstack obstack;
196   char *start_of_obstack;
197   FILE *ks_file = 0;
198   asymbol **out = table;
199   asymbol **end = table + size;
200   asymbol **sym;
201
202   if (!keepsyms_file || size == 0)
203     return end;
204   obstack_init (&obstack);
205   obstack_alloc (&obstack, 1);
206   obstack_finish (&obstack);
207   start_of_obstack = obstack_alloc (&obstack, 1);
208   ks_file = fopen (keepsyms_file, "r");
209   if (!ks_file)
210     {
211       info ("%X%P: can't open keep-symbols file `%s'\n", keepsyms_file);
212       goto egress;
213     }
214   errno = 0;
215
216 #define KEEP(S) \
217   do { asymbol **p=(S), *tmp=*out; *out=*p; *p=tmp; out++; } while (0)
218
219   while (!feof (ks_file) && !ferror (ks_file))
220     {
221       int c;
222       char *ptr;
223       int found = 0;
224
225       obstack_free (&obstack, start_of_obstack);
226       do
227         {
228           c = getc (ks_file);
229           if (c == '\n')
230             c = 0;
231           obstack_1grow (&obstack, c);
232         }
233       while (c > 0);
234       if (c == EOF)
235         {
236           if (!feof (ks_file))
237             /* error occurred */
238             {
239               info ("%X%P: error reading keep-symbols file `%s': %E\n",
240                     keepsyms_file);
241               out = end;
242               goto egress;
243             }
244           if (obstack_next_free (&obstack) != obstack_base (&obstack) + 1)
245             /* eof in middle of symbol */
246             {
247               info ("%X%P: eof reached mid-line while reading keep-symbols file `%s'\n",
248                     keepsyms_file);
249               out = end;
250               goto egress;
251             }
252           /* All okay -- no incomplete lines, EOF reached.  */
253           break;
254         }
255       ptr = obstack_next_free (&obstack) - 2;
256       /* discard trailing trash */
257       while (*ptr == ' '
258              || *ptr == '\t')
259         *ptr-- = 0;
260       ptr = obstack_base (&obstack);
261       for (sym = out; sym < end; sym++)
262         if (!strcmp ((*sym)->name, ptr))
263           {
264             KEEP (sym);
265             found = 1;
266           }
267       if (!found)
268         info ("%P: symbol `%s' (requested to be kept) not found\n", ptr);
269     }
270   /* It'd be slightly faster to move this pass above the previous one,
271      but that'd mean any symbols preserved in this pass would generate
272      warnings if they were also listed in the keepsyms file.  */
273   for (sym = out; sym < end; sym++)
274     {
275       asymbol *s = *sym;
276       if (s->section == &bfd_und_section
277           || s->section == &bfd_com_section
278           || s->flags & BSF_KEEP_G)
279         KEEP (sym);
280     }
281  egress:
282   obstack_free (&obstack, start_of_obstack);
283   if (ks_file)
284     fclose (ks_file);
285   return out;
286 }
287
288 static void
289 list_file_locals (entry)
290 lang_input_statement_type *entry;
291 {
292   asymbol **q;
293   fprintf (config.map_file, "\nLocal symbols of ");
294   minfo("%I", entry);
295   fprintf (config.map_file, ":\n\n");
296   if (entry->asymbols) {
297     for (q = entry->asymbols; *q; q++) 
298       {
299         asymbol *p = *q;
300         /* If this is a definition,
301            update it if necessary by this file's start address.  */
302         if (p->flags & BSF_LOCAL)
303          info("  %V %s\n",p->value, p->name);
304       }
305   }
306 }
307
308
309 static void
310 DEFUN(print_file_stuff,(f),
311       lang_input_statement_type *f)
312 {
313   fprintf (config.map_file,"  %s\n", f->filename);
314   if (f->just_syms_flag) 
315   {
316     fprintf (config.map_file, " symbols only\n");
317   }
318   else 
319   {
320     asection *s;
321     if (true || option_longmap) {
322       for (s = f->the_bfd->sections;
323            s != (asection *)NULL;
324            s = s->next) {
325         print_address(s->output_offset);
326         if (s->reloc_done)
327         {
328           fprintf (config.map_file, " %08x 2**%2ud %s\n",
329                    (unsigned)bfd_get_section_size_after_reloc(s),
330                    s->alignment_power, s->name);
331         }
332             
333         else 
334         {
335           fprintf (config.map_file, " %08x 2**%2ud %s\n",
336                    (unsigned)bfd_get_section_size_before_reloc(s),
337                    s->alignment_power, s->name);
338         }
339       }
340     }
341     else
342     {         
343       for (s = f->the_bfd->sections;
344            s != (asection *)NULL;
345            s = s->next) {
346         fprintf(config.map_file, "%s ", s->name);
347         print_address(s->output_offset);
348         fprintf(config.map_file, "(%x)", (unsigned)bfd_get_section_size_after_reloc(s));
349       }
350       fprintf(config.map_file, "hex \n");
351     }
352   }
353   fprintf (config.map_file, "\n");
354 }
355
356 void
357 ldsym_print_symbol_table ()
358 {
359   fprintf (config.map_file, "**FILES**\n\n");
360
361   lang_for_each_file(print_file_stuff);
362
363   fprintf(config.map_file, "**GLOBAL SYMBOLS**\n\n");
364   fprintf(config.map_file, "offset    section    offset   symbol\n");
365   {
366     register ldsym_type *sp;
367
368     for (sp = symbol_head; sp; sp = sp->next)
369       {
370         if (sp->flags & SYM_INDIRECT) {
371           fprintf(config.map_file,"indirect %s to %s\n",
372                   sp->name, (((ldsym_type *)(sp->sdefs_chain))->name));
373         }
374         else {
375           if (sp->sdefs_chain) 
376             {
377               asymbol *defsym = *(sp->sdefs_chain);
378               asection *defsec = bfd_get_section(defsym);
379               print_address(defsym->value);
380               if (defsec)
381                 {
382                   fprintf(config.map_file, "  %-10s",
383                          bfd_section_name(output_bfd,
384                                           defsec));
385                   print_space();
386                   print_address(defsym->value+defsec->vma);
387
388                 }
389               else 
390                 {
391                   fprintf(config.map_file, "         .......");
392                 }
393
394             }   
395
396
397           if (sp->scoms_chain) {
398             fprintf(config.map_file, "common               ");
399             print_address((*(sp->scoms_chain))->value);
400             fprintf(config.map_file, " %s ",sp->name);
401           }
402           else if (sp->sdefs_chain) {
403             fprintf(config.map_file, " %s ",sp->name);
404           }
405           else {
406             fprintf(config.map_file, "undefined                     ");
407             fprintf(config.map_file, "%s ",sp->name);
408
409           }
410         }
411         print_nl();
412
413       }
414   }
415   if (option_longmap) {
416     lang_for_each_file(list_file_locals);
417   }
418 }
419
420 extern lang_output_section_statement_type *create_object_symbols;
421 extern char lprefix;
422 static asymbol **
423 write_file_locals(output_buffer)
424 asymbol **output_buffer;
425 {
426   LANG_FOR_EACH_INPUT_STATEMENT(entry)
427   {
428     /* Run trough the symbols and work out what to do with them */
429     unsigned int i;
430
431     /* Add one for the filename symbol if needed */
432     if (create_object_symbols 
433         != (lang_output_section_statement_type *)NULL) {
434       asection *s;
435       for (s = entry->the_bfd->sections;
436            s != (asection *)NULL;
437            s = s->next) {
438         if (s->output_section == create_object_symbols->bfd_section) {
439           /* Add symbol to this section */
440           asymbol * newsym  =
441            (asymbol *)bfd_make_empty_symbol(entry->the_bfd);
442           newsym->name = entry->local_sym_name;
443           /* The symbol belongs to the output file's text section */
444
445           /* The value is the start of this section in the output file*/
446           newsym->value  = 0;
447           /* FIXME: Usurping BSF_KEEP_G flag, since it's defined as
448              "used by the linker" and I can't find any other code that
449              uses it.  Should be a cleaner way of doing this (like an
450              "application flags" field in the symbol structure?).  */
451           newsym->flags = BSF_LOCAL | BSF_KEEP_G;
452           newsym->section = s;
453           *output_buffer++ = newsym;
454           break;
455         }
456       }
457     }
458     for (i = 0; i < entry->symbol_count; i++) 
459     {
460       asymbol *p = entry->asymbols[i];
461       /* FIXME, temporary hack, since not all of ld knows about the new abs section convention */
462
463       if (p->section == 0)
464        p->section = &bfd_abs_section;
465       if (flag_is_global(p->flags) )
466       {
467         /* We are only interested in outputting 
468            globals at this stage in special circumstances */
469         if (p->the_bfd == entry->the_bfd 
470             && flag_is_not_at_end(p->flags)) {
471           /* And this is one of them */
472           *(output_buffer++) = p;
473           p->flags |= BSF_KEEP;
474         }
475       }
476       else {
477         if (flag_is_debugger(p->flags)) 
478         {
479           /* Only keep the debugger symbols if no stripping required */
480           if (strip_symbols == STRIP_NONE) {
481             *output_buffer++ = p;
482           }
483         }
484         else if (p->section == &bfd_und_section
485                  || p->section == &bfd_com_section)
486         {
487           /* These must be global.  */
488         }
489         else if (flag_is_ordinary_local(p->flags))
490         {
491           if (discard_locals == DISCARD_ALL)
492           {  }
493           else if (discard_locals == DISCARD_L &&
494                    (p->name[0] == lprefix)) 
495           {  }
496           else if (p->flags ==  BSF_WARNING) 
497           {  }
498           else 
499           { *output_buffer++ = p; }
500         }
501         else if (p->flags & BSF_CTOR) {
502           /* Throw it away */
503         }
504         else
505         {
506           FAIL();
507         }
508       }
509     }
510
511
512   }
513   return output_buffer;
514 }
515
516
517 static asymbol **
518 write_file_globals(symbol_table)
519 asymbol **symbol_table;
520 {
521   FOR_EACH_LDSYM(sp)
522     {
523       if ((sp->flags & SYM_INDIRECT) == 0 && sp->sdefs_chain != (asymbol **)NULL) {
524         asymbol *bufp = (*(sp->sdefs_chain));
525
526         if ((bufp->flags & BSF_KEEP) ==0) {
527           ASSERT(bufp != (asymbol *)NULL);
528
529           bufp->name = sp->name;
530
531           if (sp->scoms_chain != (asymbol **)NULL)      
532
533             {
534               /* 
535                  defined as common but not allocated, this happens
536                  only with -r and not -d, write out a common
537                  definition
538                  */
539               bufp = *(sp->scoms_chain);
540             }
541           *symbol_table++ = bufp;
542         }
543       }
544       else if (sp->scoms_chain != (asymbol **)NULL) {
545         /* This symbol is a common - just output */
546         asymbol *bufp = (*(sp->scoms_chain));
547         *symbol_table++ = bufp;
548       }
549       else if (sp->srefs_chain != (asymbol **)NULL) {
550         /* This symbol is undefined but has a reference */
551         asymbol *bufp = (*(sp->srefs_chain));
552         *symbol_table++ = bufp;
553       }
554       else {
555         /*
556            This symbol has neither defs nor refs, it must have come
557            from the command line, since noone has used it it has no
558            data attatched, so we'll ignore it 
559            */
560       }
561     }
562   return symbol_table;
563 }
564
565 void
566 ldsym_write()
567 {
568   if (keepsyms_file != 0
569       && strip_symbols != STRIP_SOME)
570     {
571       info ("%P `-retain-symbols-file' overrides `-s' and `-S'\n");
572       strip_symbols = STRIP_SOME;
573     }
574   if (strip_symbols != STRIP_ALL) {
575     /* We know the maximum size of the symbol table -
576        it's the size of all the global symbols ever seen +
577        the size of all the symbols from all the files +
578        the number of files (for the per file symbols)
579        +1 (for the null at the end)
580        */
581     extern unsigned int total_files_seen;
582     extern unsigned int total_symbols_seen;
583
584     asymbol **  symbol_table =  (asymbol **) 
585       ldmalloc ((bfd_size_type)(global_symbol_count +
586                          total_files_seen +
587                          total_symbols_seen + 1) *     sizeof (asymbol *));
588     asymbol ** tablep = write_file_locals(symbol_table);
589
590     tablep = write_file_globals(tablep);
591     tablep = process_keepsyms (symbol_table, tablep - symbol_table);
592
593     *tablep =  (asymbol *)NULL;
594     bfd_set_symtab(output_bfd, symbol_table, (unsigned)( tablep - symbol_table));
595   }
596 }
597
598 /*
599 return true if the supplied symbol name is not in the 
600 linker symbol table
601 */
602 boolean 
603 DEFUN(ldsym_undefined,(sym),
604       CONST char *sym)
605 {
606   ldsym_type *from_table = ldsym_get_soft(sym);
607   if (from_table != (ldsym_type *)NULL) 
608   {
609     if (from_table->sdefs_chain != (asymbol **)NULL) return false;
610   }
611   return true;
612 }
613
614 void
615 DEFUN_VOID(ldsym_init)
616 {
617   obstack_begin(&global_sym_obstack, 20000);
618 }
This page took 0.05687 seconds and 4 git commands to generate.