Tue Mar 30 09:40:25 1993 Steve Chamberlain (sac@thepub.cygnus.com)

* ldindr.c (add_indirect): Keep more information in the alias
	symbol chain.
	* ldlang.c (wild_doit):  Don't inherit NEVER_LOAD section
	attribute from an input section.
	* ldmain.c (Q_enter_file_symbols): Common section is NEVER_LOAD by
	default. (Q_enter_file_symbos): Indirect symbols now are known by
	their section, not a special symbol flag.
	* ldsym.c (write_file_locals): Indirect symbols aren't local.
	(write_file_globals): Write the mapping for an indirect symbol.
	* relax.c (build_it): When forced to write a NEVER_LOAD section,
	fill it with zeros.
This commit is contained in:
Steve Chamberlain
1993-03-30 17:49:00 +00:00
parent 21c7770362
commit 29f33467f2
6 changed files with 779 additions and 638 deletions

View File

@ -1,7 +1,7 @@
/* 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
@ -18,7 +18,7 @@ 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
@ -38,7 +38,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+----------+ +----------+ | |
| coms | | | +---------+
+----------+ +----------+ | udata |-----> another canonical symbol
+---------+
+---------+
@ -63,7 +63,7 @@ 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_head = (ldsym_type *) NULL;
ldsym_type **symbol_tail_ptr = &symbol_head;
CONST char *keepsyms_file;
int kept_syms;
@ -76,58 +76,61 @@ struct obstack global_sym_obstack;
/*
incremented for each symbol in the ldsym_type table
no matter what flavour it is
no matter what flavour it is
*/
unsigned int global_symbol_count;
/* IMPORTS */
extern boolean option_longmap ;
extern boolean option_longmap;
/* LOCALS */
#define TABSIZE 1009
static ldsym_type *global_symbol_hash_table[TABSIZE];
/* Compute the hash code for symbol name KEY. */
static
static
#ifdef __GNUC__
__inline
__inline
#endif
int
DEFUN(hash_string,(key),
CONST char *key)
DEFUN (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++;
}
while (*cp && l < symbol_truncate)
{
k = (((k << 1) + (k >> 14)) ^ (*cp++)) & 0x3fff;
l++;
}
return k;
}
static
#ifdef __GNUC__
__inline
__inline
#endif
ldsym_type *
DEFUN(search,(key,hashval) ,
CONST char *key AND
int hashval)
ldsym_type *
DEFUN (search, (key, hashval),
CONST char *key AND
int hashval)
{
ldsym_type *bp;
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);
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 bp;
}
return 0;
}
@ -135,8 +138,8 @@ DEFUN(search,(key,hashval) ,
/* Get the symbol table entry for the global symbol named KEY.
Create one if there is none. */
ldsym_type *
DEFUN(ldsym_get,(key),
CONST char *key)
DEFUN (ldsym_get, (key),
CONST char *key)
{
register int hashval;
register ldsym_type *bp;
@ -146,18 +149,19 @@ DEFUN(ldsym_get,(key),
hashval = hash_string (key) % TABSIZE;
/* Search the bucket. */
bp = search(key, hashval);
if(bp) {
return bp;
}
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 = (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. */
@ -176,8 +180,8 @@ DEFUN(ldsym_get,(key),
/* Like `ldsym_get' but return 0 if the symbol is not already known. */
ldsym_type *
DEFUN(ldsym_get_soft,(key),
CONST char *key)
DEFUN (ldsym_get_soft, (key),
CONST char *key)
{
register int hashval;
/* Determine which bucket. */
@ -185,12 +189,12 @@ DEFUN(ldsym_get_soft,(key),
hashval = hash_string (key) % TABSIZE;
/* Search the bucket. */
return search(key, hashval);
return search (key, hashval);
}
static asymbol **
process_keepsyms (table, size)
asymbol ** table;
asymbol **table;
int size;
{
struct obstack obstack;
@ -279,7 +283,7 @@ process_keepsyms (table, size)
|| s->flags & BSF_KEEP_G)
KEEP (sym);
}
egress:
egress:
obstack_free (&obstack, start_of_obstack);
if (ks_file)
fclose (ks_file);
@ -288,69 +292,73 @@ process_keepsyms (table, size)
static void
list_file_locals (entry)
lang_input_statement_type *entry;
lang_input_statement_type *entry;
{
asymbol **q;
fprintf (config.map_file, "\nLocal symbols of ");
minfo("%I", entry);
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,
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(" %V %s\n",p->value, p->name);
}
}
if (p->flags & BSF_LOCAL)
info (" %V %s\n", p->value, p->name);
}
}
}
static void
DEFUN(print_file_stuff,(f),
lang_input_statement_type *f)
DEFUN (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 || 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
{
fprintf (config.map_file, " %08x 2**%2ud %s\n",
(unsigned)bfd_get_section_size_before_reloc(s),
s->alignment_power, s->name);
}
}
fprintf (config.map_file, " %s\n", f->filename);
if (f->just_syms_flag)
{
fprintf (config.map_file, " symbols only\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");
else
{
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
{
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");
}
@ -359,155 +367,177 @@ ldsym_print_symbol_table ()
{
fprintf (config.map_file, "**FILES**\n\n");
lang_for_each_file(print_file_stuff);
lang_for_each_file (print_file_stuff);
fprintf(config.map_file, "**GLOBAL SYMBOLS**\n\n");
fprintf(config.map_file, "offset section offset symbol\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->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);
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) {
fprintf(config.map_file, " %s ",sp->name);
}
else {
fprintf(config.map_file, "undefined ");
fprintf(config.map_file, "%s ",sp->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();
print_nl ();
}
}
if (option_longmap) {
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;
extern char lprefix;
static asymbol **
write_file_locals(output_buffer)
asymbol **output_buffer;
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 */
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
/* 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;
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 (flag_is_global(p->flags) )
{
/* We are only interested in outputting
globals at this stage in special circumstances */
if (bfd_asymbol_bfd(p) == 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_debugger(p->flags))
{
/* Only keep the debugger symbols if no stripping required */
if (strip_symbols == STRIP_NONE) {
*output_buffer++ = p;
newsym->flags = BSF_LOCAL | BSF_KEEP_G;
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 (flag_is_global (p->flags))
{
/* We are only interested in outputting
globals at this stage in special circumstances */
if (bfd_asymbol_bfd (p) == 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 (p->section == &bfd_ind_section)
{
/* Dont think about indirect symbols */
}
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
|| bfd_is_com_section (p->section))
{
/* These must be global. */
}
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 (p->flags & BSF_CTOR)
{
/* Throw it away */
}
else
{
FAIL ();
}
}
}
else if (p->section == &bfd_und_section
|| bfd_is_com_section (p->section))
{
/* These must be global. */
}
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 (p->flags & BSF_CTOR) {
/* Throw it away */
}
else
{
FAIL();
}
}
}
}
@ -516,55 +546,79 @@ asymbol **output_buffer;
static asymbol **
write_file_globals(symbol_table)
asymbol **symbol_table;
write_file_globals (symbol_table)
asymbol **symbol_table;
{
FOR_EACH_LDSYM(sp)
{
if ((sp->flags & SYM_INDIRECT) == 0 && sp->sdefs_chain != (asymbol **)NULL) {
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);
if ((bufp->flags & BSF_KEEP) == 0)
{
ASSERT (bufp != (asymbol *) NULL);
bufp->name = sp->name;
bufp->name = sp->name;
if (sp->scoms_chain != (asymbol **)NULL)
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;
}
bufp = *(sp->scoms_chain);
}
*symbol_table++ = bufp;
}
}
else if (sp->scoms_chain != (asymbol **)NULL) {
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) {
else if (sp->srefs_chain != (asymbol **) NULL)
{
/* This symbol is undefined but has a reference */
asymbol *bufp = (*(sp->srefs_chain));
*symbol_table++ = bufp;
}
else {
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
data attatched, so we'll ignore it
*/
}
}
}
return symbol_table;
}
void
ldsym_write()
ldsym_write ()
{
if (keepsyms_file != 0
&& strip_symbols != STRIP_SOME)
@ -572,48 +626,50 @@ ldsym_write()
info ("%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 -
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)
*/
extern unsigned int total_files_seen;
extern unsigned int total_symbols_seen;
extern unsigned int total_files_seen;
extern unsigned int total_symbols_seen;
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);
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 = 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));
}
*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
return true if the supplied symbol name is not in the
linker symbol table
*/
boolean
DEFUN(ldsym_undefined,(sym),
CONST char *sym)
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;
}
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)
DEFUN_VOID (ldsym_init)
{
obstack_begin(&global_sym_obstack, 20000);
obstack_begin (&global_sym_obstack, 20000);
}