-/* Copyright (C) 1991 Free Software Foundation, Inc.
-
+/* All symbol handling for the linker
+ Copyright (C) 1991 Free Software Foundation, Inc.
+
This file is part of GLD, the Gnu Linker.
-GLD is free software; you can redistribute it and/or modify
+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 1, or (at your option)
-any later version.
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
-GLD is distributed in the hope that it will be useful,
+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 GLD; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-/*
- * $Id$
- *
- * $Log$
- * Revision 1.2 1991/03/22 23:02:38 steve
- * Brought up to sync with Intel again.
- *
- * Revision 1.1 1991/03/13 00:48:32 chrisb
- * Initial revision
- *
- * Revision 1.4 1991/03/10 09:31:36 rich
- * Modified Files:
- * Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c
- * ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h
- * ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c
- * ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c
- * ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h
- *
- * As of this round of changes, ld now builds on all hosts of (Intel960)
- * interest and copy passes my copy test on big endian hosts again.
- *
- * Revision 1.3 1991/03/06 02:28:56 sac
- * Cleaned up
- *
- * Revision 1.2 1991/02/22 17:15:06 sac
- * Added RCS keywords and copyrights
- *
-*/
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/*
-
- All symbol handling for the linker
- */
+ 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 "sysdep.h"
#include "bfd.h"
+#include "sysdep.h"
#include "ld.h"
#include "ldsym.h"
/* IMPORT */
extern bfd *output_bfd;
+extern strip_symbols_type strip_symbols;
+extern discard_locals_type discard_locals;
/* Head and tail of global symbol table chronological list */
ldsym_type *symbol_head = (ldsym_type *)NULL;
ldsym_type **symbol_tail_ptr = &symbol_head;
+extern ld_config_type config;
+
+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
static ldsym_type *global_symbol_hash_table[TABSIZE];
/* Compute the hash code for symbol name KEY. */
+static
+#ifdef __GNUC__
+__inline
+#endif
int
-hash_string (key)
- char *key;
+DEFUN(hash_string,(key),
+ CONST char *key)
{
- register char *cp;
+ register CONST char *cp;
register int k;
cp = key;
return k;
}
+static
+#ifdef __GNUC__
+__inline
+#endif ldsym_type *bp;
+ldsym_type *
+DEFUN(search,(key,hashval) ,
+ CONST char *key AND
+ int hashval)
+{
+ ldsym_type *bp;
+ for (bp = global_symbol_hash_table[hashval]; bp; bp = bp->link)
+ if (! strcmp (key, bp->name)) {
+ 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)
- char *key;
+DEFUN(ldsym_get,(key),
+ CONST char *key)
{
register int hashval;
register ldsym_type *bp;
hashval = hash_string (key) % TABSIZE;
/* Search the bucket. */
-
- for (bp = global_symbol_hash_table[hashval]; bp; bp = bp->link)
- if (! strcmp (key, bp->name))
- return bp;
+ bp = search(key, hashval);
+ if(bp) {
+ return bp;
+ }
/* Nothing was found; create a new symbol table entry. */
- bp = (ldsym_type *) ldmalloc (sizeof (ldsym_type));
+ 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 = (char *) ldmalloc (strlen (key) + 1);
- strcpy (bp->name, key);
-
-
-
-
+ 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];
/* Like `ldsym_get' but return 0 if the symbol is not already known. */
ldsym_type *
-ldsym_get_soft (key)
- char *key;
+DEFUN(ldsym_get_soft,(key),
+ CONST char *key)
{
register int hashval;
- register ldsym_type *bp;
-
/* Determine which bucket. */
hashval = hash_string (key) % TABSIZE;
/* Search the bucket. */
-
- for (bp = global_symbol_hash_table[hashval]; bp; bp = bp->link)
- if (! strcmp (key, bp->name))
- return bp;
-
- return 0;
+ return search(key, hashval);
}
lang_input_statement_type *entry;
{
asymbol **q;
- fprintf (stderr, "\nLocal symbols of ");
- info("%I", entry);
- fprintf (stderr, ":\n\n");
+ 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++)
{
static void
-print_file_stuff(f)
-lang_input_statement_type *f;
+DEFUN(print_file_stuff,(f),
+ lang_input_statement_type *f)
{
- fprintf (stderr, " %s", f->filename);
- fprintf (stderr, " ");
+ fprintf (config.map_file," %s\n", f->filename);
if (f->just_syms_flag)
- {
- fprintf (stderr, " symbols only\n");
- }
+ {
+ fprintf (config.map_file, " symbols only\n");
+ }
else
- {
- asection *s;
- if (option_longmap) {
- for (s = f->the_bfd->sections;
- s != (asection *)NULL;
- s = s->next) {
- fprintf (stderr, "%08lx %08x 2**%2ud %s\n",
- s->output_offset,
- (unsigned)s->size, s->alignment_power, s->name);
+ {
+ asection *s;
+ if (true || option_longmap) {
+ 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 {
- for (s = f->the_bfd->sections;
- s != (asection *)NULL;
- s = s->next) {
- fprintf (stderr, "%s %lx(%x) ",
- s->name,
- s->output_offset,
- (unsigned) s->size);
+
+ else
+ {
+ fprintf (config.map_file, " %08x 2**%2ud %s\n",
+ (unsigned)bfd_get_section_size_before_reloc(s),
+ s->alignment_power, s->name);
}
- fprintf (stderr, "hex \n");
}
}
+ 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 (stderr, "\nFiles:\n\n");
+ fprintf (config.map_file, "**FILES**\n\n");
lang_for_each_file(print_file_stuff);
- fprintf (stderr, "\nGlobal symbols:\n\n");
+ 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->sdefs_chain)
- {
- asymbol *defsym = *(sp->sdefs_chain);
- asection *defsec = bfd_get_section(defsym);
- fprintf(stderr,"%08lx ",defsym->value);
- if (defsec)
- {
- fprintf(stderr,"%08lx ",defsym->value+defsec->vma);
- fprintf(stderr,
- "%7s",
- bfd_section_name(output_bfd,
- defsec));
-
- }
- else
- {
- fprintf(stderr," .......");
- }
-
- }
- else {
- fprintf(stderr,"undefined");
+ 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(stderr, " common size %5lu %s",
- (*(sp->scoms_chain))->value, sp->name);
- }
- if (sp->sdefs_chain) {
- fprintf(stderr, " symbol def %08lx %s",
- (*(sp->sdefs_chain))->value,
- sp->name);
- }
- else {
- fprintf(stderr, " undefined %s",
- sp->name);
+ }
+
+
+ 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);
+
+ }
}
- fprintf(stderr, "\n");
+ print_nl();
}
}
- lang_for_each_file(list_file_locals);
+ if (option_longmap) {
+ lang_for_each_file(list_file_locals);
+ }
}
extern lang_output_section_statement_type *create_object_symbols;
write_file_locals(output_buffer)
asymbol **output_buffer;
{
-LANG_FOR_EACH_INPUT_STATEMENT(entry)
+ 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;
+ newsym->flags = BSF_LOCAL;
+ newsym->section = s;
+ *output_buffer++ = newsym;
+ break;
+ }
+ }
+ }
+ for (i = 0; i < entry->symbol_count; i++)
{
- /* 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;
- newsym->flags = BSF_LOCAL;
- newsym->section = s;
- *output_buffer++ = newsym;
- break;
- }
+ 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 (flag_is_global(p->flags) )
+ {
+ /* We are only interested in outputting
+ globals at this stage in special circumstances */
+ if (p->the_bfd == entry->the_bfd
+ && flag_is_not_at_end(p->flags)) {
+ /* And this is one of them */
+ *(output_buffer++) = p;
+ p->flags |= BSF_KEEP;
}
}
- for (i = 0; i < entry->symbol_count; i++)
+ else {
+ if (flag_is_ordinary_local(p->flags))
{
- asymbol *p = entry->asymbols[i];
-
- if (flag_is_global(p->flags) || flag_is_absolute(p->flags))
- {
- /* We are only interested in outputting
- globals at this stage in special circumstances */
- if (p->the_bfd == entry->the_bfd
- && flag_is_not_at_end(p->flags)) {
- /* And this is one of them */
- *(output_buffer++) = p;
- p->flags |= BSF_KEEP;
- }
- }
- else {
- if (flag_is_ordinary_local(p->flags))
- {
- if (discard_locals == DISCARD_ALL)
- { }
- else if (discard_locals == DISCARD_L &&
- (p->name[0] == lprefix))
- { }
- else if (p->flags == BSF_WARNING)
- { }
- else
- { *output_buffer++ = p; }
- }
- else if (flag_is_debugger(p->flags))
- {
- /* Only keep the debugger symbols if no stripping required */
- if (strip_symbols == STRIP_NONE) {
- *output_buffer++ = p;
- }
- }
- else if (flag_is_undefined(p->flags))
- { /* This must be global */
- }
- else if (flag_is_common(p->flags)) {
- /* And so must this */
- }
- else if (p->flags & BSF_CTOR) {
- /* Throw it away */
- }
-else
- {
- FAIL();
- }
+ if (discard_locals == DISCARD_ALL)
+ { }
+ else if (discard_locals == DISCARD_L &&
+ (p->name[0] == lprefix))
+ { }
+ else if (p->flags == BSF_WARNING)
+ { }
+ else
+ { *output_buffer++ = p; }
+ }
+ else if (flag_is_debugger(p->flags))
+ {
+ /* Only keep the debugger symbols if no stripping required */
+ if (strip_symbols == STRIP_NONE) {
+ *output_buffer++ = p;
}
}
+ else if (p->section == &bfd_und_section)
+ { /* This must be global */
+ }
+ else if (p->section == &bfd_com_section) {
+ /* And so must this */
+ }
+ else if (p->flags & BSF_CTOR) {
+ /* Throw it away */
+ }
+ else
+ {
+ FAIL();
+ }
+ }
+ }
- }
+ }
return output_buffer;
}
{
FOR_EACH_LDSYM(sp)
{
- if (sp->sdefs_chain != (asymbol **)NULL) {
+ if ((sp->flags & SYM_INDIRECT) == 0 && sp->sdefs_chain != (asymbol **)NULL) {
asymbol *bufp = (*(sp->sdefs_chain));
if ((bufp->flags & BSF_KEEP) ==0) {
extern unsigned int total_symbols_seen;
asymbol ** symbol_table = (asymbol **)
- ldmalloc ((size_t)(global_symbol_count +
+ ldmalloc ((bfd_size_type)(global_symbol_count +
total_files_seen +
total_symbols_seen + 1) * sizeof (asymbol *));
asymbol ** tablep = write_file_locals(symbol_table);
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
+DEFUN(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
+DEFUN_VOID(ldsym_init)
+{
+ obstack_begin(&global_sym_obstack, 20000);
+}