-y support
[platform/upstream/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 steve@cygnus.com
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 extern int symbol_truncate;
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   register int l = 0;
104   cp = key;
105   k = 0;
106   while (*cp && l < symbol_truncate) {
107     k = (((k << 1) + (k >> 14)) ^ (*cp++)) & 0x3fff;
108     l++;
109   }
110   return k;
111 }
112
113 static
114 #ifdef __GNUC__
115 __inline
116 #endif ldsym_type *bp;
117 ldsym_type *
118 DEFUN(search,(key,hashval) ,
119       CONST char *key AND
120       int hashval)
121 {
122   ldsym_type *bp;                                  
123   for (bp = global_symbol_hash_table[hashval]; bp; bp = bp->link)
124     if (! strncmp (key, bp->name, symbol_truncate)) {
125       if (bp->flags & SYM_INDIRECT) {   
126         /* Use the symbol we're aliased to instead */
127         return (ldsym_type *)(bp->sdefs_chain);
128       }
129       return bp;
130     }
131   return 0;
132 }
133
134
135 /* Get the symbol table entry for the global symbol named KEY.
136    Create one if there is none.  */
137 ldsym_type *
138 DEFUN(ldsym_get,(key),
139       CONST     char *key)
140 {
141   register int hashval;
142   register ldsym_type *bp;
143
144   /* Determine the proper bucket.  */
145
146   hashval = hash_string (key) % TABSIZE;
147
148   /* Search the bucket.  */
149   bp = search(key, hashval);
150   if(bp) {
151     return bp;
152   }
153
154   /* Nothing was found; create a new symbol table entry.  */
155
156   bp = (ldsym_type *) obstack_alloc (&global_sym_obstack, (bfd_size_type)(sizeof (ldsym_type)));
157   bp->srefs_chain = (asymbol **)NULL;
158   bp->sdefs_chain = (asymbol **)NULL;
159   bp->scoms_chain = (asymbol **)NULL;
160   bp->name = obstack_copy(&global_sym_obstack,  key, strlen(key)+1);
161   bp->flags = 0;
162   /* Add the entry to the bucket.  */
163
164   bp->link = global_symbol_hash_table[hashval];
165   global_symbol_hash_table[hashval] = bp;
166
167   /* Keep the chronological list up to date too */
168   *symbol_tail_ptr = bp;
169   symbol_tail_ptr = &bp->next;
170   bp->next = 0;
171   global_symbol_count++;
172
173   return bp;
174 }
175
176 /* Like `ldsym_get' but return 0 if the symbol is not already known.  */
177
178 ldsym_type *
179 DEFUN(ldsym_get_soft,(key),
180       CONST char *key)
181 {
182   register int hashval;
183   /* Determine which bucket.  */
184
185   hashval = hash_string (key) % TABSIZE;
186
187   /* Search the bucket.  */
188   return search(key, hashval);
189 }
190
191 static asymbol **
192 process_keepsyms (table, size)
193      asymbol ** table;
194      int size;
195 {
196   struct obstack obstack;
197   char *start_of_obstack;
198   FILE *ks_file = 0;
199   asymbol **out = table;
200   asymbol **end = table + size;
201   asymbol **sym;
202
203   if (!keepsyms_file || size == 0)
204     return end;
205   obstack_init (&obstack);
206   obstack_alloc (&obstack, 1);
207   obstack_finish (&obstack);
208   start_of_obstack = obstack_alloc (&obstack, 1);
209   ks_file = fopen (keepsyms_file, "r");
210   if (!ks_file)
211     {
212       info ("%X%P: can't open keep-symbols file `%s'\n", keepsyms_file);
213       goto egress;
214     }
215   errno = 0;
216
217 #define KEEP(S) \
218   do { asymbol **p=(S), *tmp=*out; *out=*p; *p=tmp; out++; } while (0)
219
220   while (!feof (ks_file) && !ferror (ks_file))
221     {
222       int c;
223       char *ptr;
224       int found = 0;
225
226       obstack_free (&obstack, start_of_obstack);
227       do
228         {
229           c = getc (ks_file);
230           if (c == '\n')
231             c = 0;
232           obstack_1grow (&obstack, c);
233         }
234       while (c > 0);
235       if (c == EOF)
236         {
237           if (!feof (ks_file))
238             /* error occurred */
239             {
240               info ("%X%P: error reading keep-symbols file `%s': %E\n",
241                     keepsyms_file);
242               out = end;
243               goto egress;
244             }
245           if (obstack_next_free (&obstack) != obstack_base (&obstack) + 1)
246             /* eof in middle of symbol */
247             {
248               info ("%X%P: eof reached mid-line while reading keep-symbols file `%s'\n",
249                     keepsyms_file);
250               out = end;
251               goto egress;
252             }
253           /* All okay -- no incomplete lines, EOF reached.  */
254           break;
255         }
256       ptr = obstack_next_free (&obstack) - 2;
257       /* discard trailing trash */
258       while (*ptr == ' '
259              || *ptr == '\t')
260         *ptr-- = 0;
261       ptr = obstack_base (&obstack);
262       for (sym = out; sym < end; sym++)
263         if (!strncmp ((*sym)->name, ptr, symbol_truncate))
264           {
265             KEEP (sym);
266             found = 1;
267           }
268       if (!found)
269         info ("%P: symbol `%s' (requested to be kept) not found\n", ptr);
270     }
271   /* It'd be slightly faster to move this pass above the previous one,
272      but that'd mean any symbols preserved in this pass would generate
273      warnings if they were also listed in the keepsyms file.  */
274   for (sym = out; sym < end; sym++)
275     {
276       asymbol *s = *sym;
277       if (s->section == &bfd_und_section
278           || s->section == &bfd_com_section
279           || s->flags & BSF_KEEP_G)
280         KEEP (sym);
281     }
282  egress:
283   obstack_free (&obstack, start_of_obstack);
284   if (ks_file)
285     fclose (ks_file);
286   return out;
287 }
288
289 static void
290 list_file_locals (entry)
291 lang_input_statement_type *entry;
292 {
293   asymbol **q;
294   fprintf (config.map_file, "\nLocal symbols of ");
295   minfo("%I", entry);
296   fprintf (config.map_file, ":\n\n");
297   if (entry->asymbols) {
298     for (q = entry->asymbols; *q; q++) 
299       {
300         asymbol *p = *q;
301         /* If this is a definition,
302            update it if necessary by this file's start address.  */
303         if (p->flags & BSF_LOCAL)
304          info("  %V %s\n",p->value, p->name);
305       }
306   }
307 }
308
309
310 static void
311 DEFUN(print_file_stuff,(f),
312       lang_input_statement_type *f)
313 {
314   fprintf (config.map_file,"  %s\n", f->filename);
315   if (f->just_syms_flag) 
316   {
317     fprintf (config.map_file, " symbols only\n");
318   }
319   else 
320   {
321     asection *s;
322     if (true || option_longmap) {
323       for (s = f->the_bfd->sections;
324            s != (asection *)NULL;
325            s = s->next) {
326         print_address(s->output_offset);
327         if (s->reloc_done)
328         {
329           fprintf (config.map_file, " %08x 2**%2ud %s\n",
330                    (unsigned)bfd_get_section_size_after_reloc(s),
331                    s->alignment_power, s->name);
332         }
333             
334         else 
335         {
336           fprintf (config.map_file, " %08x 2**%2ud %s\n",
337                    (unsigned)bfd_get_section_size_before_reloc(s),
338                    s->alignment_power, s->name);
339         }
340       }
341     }
342     else
343     {         
344       for (s = f->the_bfd->sections;
345            s != (asection *)NULL;
346            s = s->next) {
347         fprintf(config.map_file, "%s ", s->name);
348         print_address(s->output_offset);
349         fprintf(config.map_file, "(%x)", (unsigned)bfd_get_section_size_after_reloc(s));
350       }
351       fprintf(config.map_file, "hex \n");
352     }
353   }
354   fprintf (config.map_file, "\n");
355 }
356
357 void
358 ldsym_print_symbol_table ()
359 {
360   fprintf (config.map_file, "**FILES**\n\n");
361
362   lang_for_each_file(print_file_stuff);
363
364   fprintf(config.map_file, "**GLOBAL SYMBOLS**\n\n");
365   fprintf(config.map_file, "offset    section    offset   symbol\n");
366   {
367     register ldsym_type *sp;
368
369     for (sp = symbol_head; sp; sp = sp->next)
370       {
371         if (sp->flags & SYM_INDIRECT) {
372           fprintf(config.map_file,"indirect %s to %s\n",
373                   sp->name, (((ldsym_type *)(sp->sdefs_chain))->name));
374         }
375         else {
376           if (sp->sdefs_chain) 
377             {
378               asymbol *defsym = *(sp->sdefs_chain);
379               asection *defsec = bfd_get_section(defsym);
380               print_address(defsym->value);
381               if (defsec)
382                 {
383                   fprintf(config.map_file, "  %-10s",
384                          bfd_section_name(output_bfd,
385                                           defsec));
386                   print_space();
387                   print_address(defsym->value+defsec->vma);
388
389                 }
390               else 
391                 {
392                   fprintf(config.map_file, "         .......");
393                 }
394
395             }   
396
397
398           if (sp->scoms_chain) {
399             fprintf(config.map_file, "common               ");
400             print_address((*(sp->scoms_chain))->value);
401             fprintf(config.map_file, " %s ",sp->name);
402           }
403           else if (sp->sdefs_chain) {
404             fprintf(config.map_file, " %s ",sp->name);
405           }
406           else {
407             fprintf(config.map_file, "undefined                     ");
408             fprintf(config.map_file, "%s ",sp->name);
409
410           }
411         }
412         print_nl();
413
414       }
415   }
416   if (option_longmap) {
417     lang_for_each_file(list_file_locals);
418   }
419 }
420
421 extern lang_output_section_statement_type *create_object_symbols;
422 extern char lprefix;
423 static asymbol **
424 write_file_locals(output_buffer)
425 asymbol **output_buffer;
426 {
427   LANG_FOR_EACH_INPUT_STATEMENT(entry)
428   {
429     /* Run trough the symbols and work out what to do with them */
430     unsigned int i;
431
432     /* Add one for the filename symbol if needed */
433     if (create_object_symbols 
434         != (lang_output_section_statement_type *)NULL) {
435       asection *s;
436       for (s = entry->the_bfd->sections;
437            s != (asection *)NULL;
438            s = s->next) {
439         if (s->output_section == create_object_symbols->bfd_section) {
440           /* Add symbol to this section */
441           asymbol * newsym  =
442            (asymbol *)bfd_make_empty_symbol(entry->the_bfd);
443           newsym->name = entry->local_sym_name;
444           /* The symbol belongs to the output file's text section */
445
446           /* The value is the start of this section in the output file*/
447           newsym->value  = 0;
448           /* FIXME: Usurping BSF_KEEP_G flag, since it's defined as
449              "used by the linker" and I can't find any other code that
450              uses it.  Should be a cleaner way of doing this (like an
451              "application flags" field in the symbol structure?).  */
452           newsym->flags = BSF_LOCAL | BSF_KEEP_G;
453           newsym->section = s;
454           *output_buffer++ = newsym;
455           break;
456         }
457       }
458     }
459     for (i = 0; i < entry->symbol_count; i++) 
460     {
461       asymbol *p = entry->asymbols[i];
462       /* FIXME, temporary hack, since not all of ld knows about the new abs section convention */
463
464       if (p->section == 0)
465        p->section = &bfd_abs_section;
466       if (flag_is_global(p->flags) )
467       {
468         /* We are only interested in outputting 
469            globals at this stage in special circumstances */
470         if (p->the_bfd == entry->the_bfd 
471             && flag_is_not_at_end(p->flags)) {
472           /* And this is one of them */
473           *(output_buffer++) = p;
474           p->flags |= BSF_KEEP;
475         }
476       }
477       else {
478         if (flag_is_debugger(p->flags)) 
479         {
480           /* Only keep the debugger symbols if no stripping required */
481           if (strip_symbols == STRIP_NONE) {
482             *output_buffer++ = p;
483           }
484         }
485         else if (p->section == &bfd_und_section
486                  || p->section == &bfd_com_section)
487         {
488           /* These must be global.  */
489         }
490         else if (flag_is_ordinary_local(p->flags))
491         {
492           if (discard_locals == DISCARD_ALL)
493           {  }
494           else if (discard_locals == DISCARD_L &&
495                    (p->name[0] == lprefix)) 
496           {  }
497           else if (p->flags ==  BSF_WARNING) 
498           {  }
499           else 
500           { *output_buffer++ = p; }
501         }
502         else if (p->flags & BSF_CTOR) {
503           /* Throw it away */
504         }
505         else
506         {
507           FAIL();
508         }
509       }
510     }
511
512
513   }
514   return output_buffer;
515 }
516
517
518 static asymbol **
519 write_file_globals(symbol_table)
520 asymbol **symbol_table;
521 {
522   FOR_EACH_LDSYM(sp)
523     {
524       if ((sp->flags & SYM_INDIRECT) == 0 && sp->sdefs_chain != (asymbol **)NULL) {
525         asymbol *bufp = (*(sp->sdefs_chain));
526
527         if ((bufp->flags & BSF_KEEP) ==0) {
528           ASSERT(bufp != (asymbol *)NULL);
529
530           bufp->name = sp->name;
531
532           if (sp->scoms_chain != (asymbol **)NULL)      
533
534             {
535               /* 
536                  defined as common but not allocated, this happens
537                  only with -r and not -d, write out a common
538                  definition
539                  */
540               bufp = *(sp->scoms_chain);
541             }
542           *symbol_table++ = bufp;
543         }
544       }
545       else if (sp->scoms_chain != (asymbol **)NULL) {
546         /* This symbol is a common - just output */
547         asymbol *bufp = (*(sp->scoms_chain));
548         *symbol_table++ = bufp;
549       }
550       else if (sp->srefs_chain != (asymbol **)NULL) {
551         /* This symbol is undefined but has a reference */
552         asymbol *bufp = (*(sp->srefs_chain));
553         *symbol_table++ = bufp;
554       }
555       else {
556         /*
557            This symbol has neither defs nor refs, it must have come
558            from the command line, since noone has used it it has no
559            data attatched, so we'll ignore it 
560            */
561       }
562     }
563   return symbol_table;
564 }
565
566 void
567 ldsym_write()
568 {
569   if (keepsyms_file != 0
570       && strip_symbols != STRIP_SOME)
571     {
572       info ("%P `-retain-symbols-file' overrides `-s' and `-S'\n");
573       strip_symbols = STRIP_SOME;
574     }
575   if (strip_symbols != STRIP_ALL) {
576     /* We know the maximum size of the symbol table -
577        it's the size of all the global symbols ever seen +
578        the size of all the symbols from all the files +
579        the number of files (for the per file symbols)
580        +1 (for the null at the end)
581        */
582     extern unsigned int total_files_seen;
583     extern unsigned int total_symbols_seen;
584
585     asymbol **  symbol_table =  (asymbol **) 
586       ldmalloc ((bfd_size_type)(global_symbol_count +
587                          total_files_seen +
588                          total_symbols_seen + 1) *     sizeof (asymbol *));
589     asymbol ** tablep = write_file_locals(symbol_table);
590
591     tablep = write_file_globals(tablep);
592     tablep = process_keepsyms (symbol_table, tablep - symbol_table);
593
594     *tablep =  (asymbol *)NULL;
595     bfd_set_symtab(output_bfd, symbol_table, (unsigned)( tablep - symbol_table));
596   }
597 }
598
599 /*
600 return true if the supplied symbol name is not in the 
601 linker symbol table
602 */
603 boolean 
604 DEFUN(ldsym_undefined,(sym),
605       CONST char *sym)
606 {
607   ldsym_type *from_table = ldsym_get_soft(sym);
608   if (from_table != (ldsym_type *)NULL) 
609   {
610     if (from_table->sdefs_chain != (asymbol **)NULL) return false;
611   }
612   return true;
613 }
614
615 void
616 DEFUN_VOID(ldsym_init)
617 {
618   obstack_begin(&global_sym_obstack, 20000);
619 }