diff options
Diffstat (limited to 'ld/ldsym.c')
-rw-r--r-- | ld/ldsym.c | 673 |
1 files changed, 0 insertions, 673 deletions
diff --git a/ld/ldsym.c b/ld/ldsym.c deleted file mode 100644 index 6de790d..0000000 --- a/ld/ldsym.c +++ /dev/null @@ -1,673 +0,0 @@ -/* All symbol handling for the linker - Copyright (C) 1991 Free Software Foundation, Inc. - Written by Steve Chamberlain steve@cygnus.com - -This file is part of GLD, the Gnu Linker. - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - -/* - We keep a hash table of global symbols. Each entry in a hash table - is called an ldsym_type. Each has three chains; a pointer to a - chain of definitions for the symbol (hopefully one long), a pointer - to a chain of references to the symbol, and a pointer to a chain of - common symbols. Each pointer points into the canonical symbol table - provided by bfd, each one of which points to an asymbol. During - linkage, the linker uses the udata field to point to the next entry - in a canonical table.... - - - ld_sym - | | - +----------+ +----------+ - | defs | a canonical symbol table - +----------+ +----------+ - | refs | -----> | one entry| -----> asymbol - +----------+ +----------+ | | - | coms | | | +---------+ - +----------+ +----------+ | udata |-----> another canonical - +---------+ symbol - - - - It is very simple to make all the symbol pointers point to the same - definition - just run down the chain and make the asymbols pointers - within the canonical table point to the asymbol attacthed to the - definition of the symbol. - -*/ - -#include "bfd.h" -#include "sysdep.h" - -#include "ld.h" -#include "ldsym.h" -#include "ldmisc.h" -#include "ldexp.h" -#include "ldlang.h" -#include "mri.h" -#include "ldmain.h" - -/* Head and tail of global symbol table chronological list */ - -ldsym_type *symbol_head = (ldsym_type *) NULL; -ldsym_type **symbol_tail_ptr = &symbol_head; -CONST char *keepsyms_file; -int kept_syms; - -struct obstack global_sym_obstack; -#define obstack_chunk_alloc ldmalloc -#define obstack_chunk_free free - -/* - incremented for each symbol in the ldsym_type table - no matter what flavour it is -*/ -unsigned int global_symbol_count; - -/* LOCALS */ -#define TABSIZE 1009 -static ldsym_type *global_symbol_hash_table[TABSIZE]; - -#ifndef __GNUC__ -#define __inline -#endif - -static __inline int hash_string PARAMS ((const char *key)); -static __inline ldsym_type *search PARAMS ((const char *key, int hashval)); -static asymbol **process_keepsyms PARAMS ((asymbol **table, int size)); -static void print_file_stuff PARAMS ((lang_input_statement_type * f)); -static asymbol **write_file_locals PARAMS ((asymbol **output_buffer)); -static asymbol **write_file_globals PARAMS ((asymbol **symbol_table)); - -/* Compute the hash code for symbol name KEY. */ -static __inline int -hash_string (key) - CONST char *key; -{ - register CONST char *cp; - register int k; - register int l = 0; - cp = key; - k = 0; - while (*cp && l < symbol_truncate) - { - k = (((k << 1) + (k >> 14)) ^ (*cp++)) & 0x3fff; - l++; - } - return k; -} - -static __inline ldsym_type * -search (key, hashval) - CONST char *key; - int hashval; -{ - ldsym_type *bp; - for (bp = global_symbol_hash_table[hashval]; bp; bp = bp->link) - if (!strncmp (key, bp->name, symbol_truncate)) - { - if (bp->flags & SYM_INDIRECT) - { - /* Use the symbol we're aliased to instead */ - return (ldsym_type *) (bp->sdefs_chain); - } - return bp; - } - return 0; -} - - -/* Get the symbol table entry for the global symbol named KEY. - Create one if there is none. */ -ldsym_type * -ldsym_get (key) - CONST char *key; -{ - register int hashval; - register ldsym_type *bp; - - /* Determine the proper bucket. */ - - hashval = hash_string (key) % TABSIZE; - - /* Search the bucket. */ - bp = search (key, hashval); - if (bp) - { - return bp; - } - - /* Nothing was found; create a new symbol table entry. */ - - bp = (ldsym_type *) obstack_alloc (&global_sym_obstack, (bfd_size_type) (sizeof (ldsym_type))); - bp->srefs_chain = (asymbol **) NULL; - bp->sdefs_chain = (asymbol **) NULL; - bp->scoms_chain = (asymbol **) NULL; - bp->name = obstack_copy (&global_sym_obstack, key, strlen (key) + 1); - bp->flags = 0; - /* Add the entry to the bucket. */ - - bp->link = global_symbol_hash_table[hashval]; - global_symbol_hash_table[hashval] = bp; - - /* Keep the chronological list up to date too */ - *symbol_tail_ptr = bp; - symbol_tail_ptr = &bp->next; - bp->next = 0; - global_symbol_count++; - - return bp; -} - -/* Like `ldsym_get' but return 0 if the symbol is not already known. */ - -ldsym_type * -ldsym_get_soft (key) - CONST char *key; -{ - register int hashval; - /* Determine which bucket. */ - - hashval = hash_string (key) % TABSIZE; - - /* Search the bucket. */ - return search (key, hashval); -} - -static asymbol ** -process_keepsyms (table, size) - asymbol **table; - int size; -{ - struct obstack obstack; - char *start_of_obstack; - FILE *ks_file = 0; - asymbol **out = table; - asymbol **end = table + size; - asymbol **sym; - - if (!keepsyms_file || size == 0) - return end; - obstack_init (&obstack); - obstack_alloc (&obstack, 1); - obstack_finish (&obstack); - start_of_obstack = obstack_alloc (&obstack, 1); - ks_file = fopen (keepsyms_file, "r"); - if (!ks_file) - { - info_msg ("%X%P: cannot open keep-symbols file `%s'\n", keepsyms_file); - goto egress; - } - errno = 0; - -#define KEEP(S) \ - do { asymbol **p = (S), *tmp = *out; *out = *p; *p = tmp; out++; } while (0) - - while (!feof (ks_file) && !ferror (ks_file)) - { - int c; - char *ptr; - int found = 0; - - obstack_free (&obstack, start_of_obstack); - do - { - c = getc (ks_file); - if (c == '\n') - c = 0; - obstack_1grow (&obstack, c); - } - while (c > 0); - if (c == EOF) - { - if (!feof (ks_file)) - /* error occurred */ - { - info_msg ("%X%P: error reading keep-symbols file `%s': %E\n", - keepsyms_file); - out = end; - goto egress; - } - if (obstack_next_free (&obstack) != obstack_base (&obstack) + 1) - /* eof in middle of symbol */ - { - info_msg ("%X%P: eof reached mid-line while reading keep-symbols file `%s'\n", - keepsyms_file); - out = end; - goto egress; - } - /* All okay -- no incomplete lines, EOF reached. */ - break; - } - ptr = obstack_next_free (&obstack) - 2; - /* discard trailing trash */ - while (*ptr == ' ' - || *ptr == '\t') - *ptr-- = 0; - ptr = obstack_base (&obstack); - for (sym = out; sym < end; sym++) - if (!strncmp ((*sym)->name, ptr, symbol_truncate)) - { - KEEP (sym); - found = 1; - } - if (!found) - info_msg ("%P: symbol `%s' (requested to be kept) not found\n", ptr); - } - /* It'd be slightly faster to move this pass above the previous one, - but that'd mean any symbols preserved in this pass would generate - warnings if they were also listed in the keepsyms file. */ - for (sym = out; sym < end; sym++) - { - asymbol *s = *sym; - if (s->section == &bfd_und_section - || bfd_is_com_section (s->section) - || s->flags & BSF_KEEP_G) - KEEP (sym); - } -egress: - obstack_free (&obstack, start_of_obstack); - if (ks_file) - fclose (ks_file); - return out; -} - -#if 0 - -/* This function is not used. */ - -static void -list_file_locals (entry) - lang_input_statement_type *entry; -{ - asymbol **q; - fprintf (config.map_file, "\nLocal symbols of "); - minfo ("%I", entry); - fprintf (config.map_file, ":\n\n"); - if (entry->asymbols) - { - for (q = entry->asymbols; *q; q++) - { - asymbol *p = *q; - /* If this is a definition, - update it if necessary by this file's start address. */ - if (p->flags & BSF_LOCAL) - info_msg (" %V %s\n", p->value, p->name); - } - } -} - -#endif - -static void -print_file_stuff (f) - lang_input_statement_type * f; -{ - fprintf (config.map_file, " %s\n", f->filename); - if (f->just_syms_flag) - { - fprintf (config.map_file, " symbols only\n"); - } - else - { - asection *s; - if (true) - { - for (s = f->the_bfd->sections; - s != (asection *) NULL; - s = s->next) - { - print_address (s->output_offset); - if (s->reloc_done) - { - fprintf (config.map_file, " %08x 2**%2ud %s\n", - (unsigned) bfd_get_section_size_after_reloc (s), - s->alignment_power, s->name); - } - - else - { - fprintf (config.map_file, " %08x 2**%2ud %s\n", - (unsigned) bfd_get_section_size_before_reloc (s), - s->alignment_power, s->name); - } - } - } - else - { - for (s = f->the_bfd->sections; - s != (asection *) NULL; - s = s->next) - { - fprintf (config.map_file, "%s ", s->name); - print_address (s->output_offset); - fprintf (config.map_file, "(%x)", (unsigned) bfd_get_section_size_after_reloc (s)); - } - fprintf (config.map_file, "hex \n"); - } - } - fprintf (config.map_file, "\n"); -} - -void -ldsym_print_symbol_table () -{ - fprintf (config.map_file, "**FILES**\n\n"); - - lang_for_each_file (print_file_stuff); - - fprintf (config.map_file, "**GLOBAL SYMBOLS**\n\n"); - fprintf (config.map_file, "offset section offset symbol\n"); - { - register ldsym_type *sp; - - for (sp = symbol_head; sp; sp = sp->next) - { - if (sp->flags & SYM_INDIRECT) - { - fprintf (config.map_file, "indirect %s to %s\n", - sp->name, (((ldsym_type *) (sp->sdefs_chain))->name)); - } - else - { - if (sp->sdefs_chain) - { - asymbol *defsym = *(sp->sdefs_chain); - asection *defsec = bfd_get_section (defsym); - print_address (defsym->value); - if (defsec) - { - fprintf (config.map_file, " %-10s", - bfd_section_name (output_bfd, - defsec)); - print_space (); - print_address (defsym->value + defsec->vma); - - } - else - { - fprintf (config.map_file, " ......."); - } - - } - - - if (sp->scoms_chain) - { - fprintf (config.map_file, "common "); - print_address ((*(sp->scoms_chain))->value); - fprintf (config.map_file, " %s ", sp->name); - } - else if (sp->sdefs_chain) - { - fprintf (config.map_file, " %s ", sp->name); - } - else - { - fprintf (config.map_file, "undefined "); - fprintf (config.map_file, "%s ", sp->name); - - } - } - print_nl (); - - } - } -} - -static asymbol ** -write_file_locals (output_buffer) - asymbol **output_buffer; -{ - LANG_FOR_EACH_INPUT_STATEMENT (entry) - { - /* Run trough the symbols and work out what to do with them */ - unsigned int i; - - /* Add one for the filename symbol if needed */ - if (create_object_symbols - != (lang_output_section_statement_type *) NULL) - { - asection *s; - for (s = entry->the_bfd->sections; - s != (asection *) NULL; - s = s->next) - { - if (s->output_section == create_object_symbols->bfd_section) - { - /* Add symbol to this section */ - asymbol *newsym = - (asymbol *) bfd_make_empty_symbol (entry->the_bfd); - newsym->name = entry->local_sym_name; - /* The symbol belongs to the output file's text section */ - - /* The value is the start of this section in the output file*/ - newsym->value = 0; - /* FIXME: Usurping BSF_KEEP_G flag, since it's defined as - "used by the linker" and I can't find any other code that - uses it. Should be a cleaner way of doing this (like an - "application flags" field in the symbol structure?). */ - newsym->flags = BSF_LOCAL | BSF_KEEP_G | BSF_FILE; - newsym->section = s; - *output_buffer++ = newsym; - break; - } - } - } - for (i = 0; i < entry->symbol_count; i++) - { - asymbol *p = entry->asymbols[i]; - /* FIXME, temporary hack, since not all of ld knows about the new abs section convention */ - - if (p->section == 0) - p->section = &bfd_abs_section; - if ((p->flags & BSF_GLOBAL) - || (p->flags & BSF_WEAK)) - { - /* If this symbol is marked as occurring now, rather than - at the end, output it now. This is used for COFF C_EXT - FCN symbols. FIXME: There must be a better way. */ - if (bfd_asymbol_bfd (p) == entry->the_bfd - && (p->flags & BSF_NOT_AT_END)) - { - *(output_buffer++) = p; - p->flags |= BSF_KEEP; - } - } - else - { - if (p->section == &bfd_ind_section) - { - /* Dont think about indirect symbols */ - } - else if (p->flags & BSF_DEBUGGING) - { - /* Only keep the debugger symbols if no stripping required */ - if (strip_symbols == STRIP_NONE) - { - *output_buffer++ = p; - } - } - else if (p->section == &bfd_und_section - || bfd_is_com_section (p->section)) - { - /* These must be global. */ - } - else if (p->flags & BSF_LOCAL) - { - if (discard_locals == DISCARD_ALL) - { - } - else if (discard_locals == DISCARD_L && - !strncmp (lprefix, p->name, lprefix_len)) - { - } - else if (p->flags == BSF_WARNING) - { - } - else - { - *output_buffer++ = p; - } - } - else if (p->flags & BSF_CONSTRUCTOR) - { - if (strip_symbols != STRIP_ALL) - { - *output_buffer++ = p; - } - } - else - { - FAIL (); - } - } - } - - - } - return output_buffer; -} - - -static asymbol ** -write_file_globals (symbol_table) - asymbol **symbol_table; -{ - FOR_EACH_LDSYM (sp) - { - if (sp->flags & SYM_INDIRECT) - { - asymbol *bufp = (*(sp->srefs_chain)); - ldsym_type *aliased_to = (ldsym_type *) (sp->sdefs_chain); - if (aliased_to->sdefs_chain) - { - asymbol *p = aliased_to->sdefs_chain[0]; - bufp->value = p->value; - bufp->section = p->section; - bufp->flags = p->flags; - } - else - { - bufp->value = 0; - bufp->flags = 0; - bufp->section = &bfd_und_section; - } - *symbol_table++ = bufp; - } - else if ((sp->flags & SYM_INDIRECT) == 0 && sp->sdefs_chain != (asymbol **) NULL) - { - asymbol *bufp = (*(sp->sdefs_chain)); - - if ((bufp->flags & BSF_KEEP) == 0) - { - ASSERT (bufp != (asymbol *) NULL); - - bufp->name = sp->name; - - if (sp->scoms_chain != (asymbol **) NULL) - - { - /* - defined as common but not allocated, this happens - only with -r and not -d, write out a common - definition - */ - bufp = *(sp->scoms_chain); - } - *symbol_table++ = bufp; - } - } - else if (sp->scoms_chain != (asymbol **) NULL) - { - /* This symbol is a common - just output */ - asymbol *bufp = (*(sp->scoms_chain)); - *symbol_table++ = bufp; - } - else if (sp->srefs_chain != (asymbol **) NULL) - { - /* This symbol is undefined but has a reference */ - asymbol *bufp = (*(sp->srefs_chain)); - *symbol_table++ = bufp; - } - else - { - /* - This symbol has neither defs nor refs, it must have come - from the command line, since noone has used it it has no - data attatched, so we'll ignore it - */ - } - } - return symbol_table; -} - -void -ldsym_write () -{ - if (keepsyms_file != 0 - && strip_symbols != STRIP_SOME) - { - info_msg ("%P: `-retain-symbols-file' overrides `-s' and `-S'\n"); - strip_symbols = STRIP_SOME; - } - if (strip_symbols != STRIP_ALL) - { - /* We know the maximum size of the symbol table - - it's the size of all the global symbols ever seen + - the size of all the symbols from all the files + - the number of files (for the per file symbols) - +1 (for the null at the end) - */ - asymbol **symbol_table = - ((asymbol **) - ldmalloc ((bfd_size_type) ((global_symbol_count - + total_files_seen - + total_symbols_seen - + 1) - * sizeof (asymbol *)))); - asymbol **tablep = write_file_locals (symbol_table); - - tablep = write_file_globals (tablep); - tablep = process_keepsyms (symbol_table, tablep - symbol_table); - - *tablep = (asymbol *) NULL; - bfd_set_symtab (output_bfd, symbol_table, (unsigned) (tablep - symbol_table)); - } -} - -/* -return true if the supplied symbol name is not in the -linker symbol table -*/ -boolean -ldsym_undefined (sym) - CONST char *sym; -{ - ldsym_type *from_table = ldsym_get_soft (sym); - if (from_table != (ldsym_type *) NULL) - { - if (from_table->sdefs_chain != (asymbol **) NULL) - return false; - } - return true; -} - -void -ldsym_init () -{ - obstack_begin (&global_sym_obstack, 20000); -} |