* linker.c (enum link_action): Add CIND.

(link_action): Change COMMON_ROW\indr from MDEF to CREF.  Change
	INDR_ROW\common from MDEF to CIND.
	(_bfd_generic_link_add_one_symbol): In CREF case, handle an
	existing symbol which is indirect rather than defined.  Add new
	CIND case.
This commit is contained in:
Ian Lance Taylor 1994-10-25 15:47:59 +00:00
parent adbae12d78
commit 9c26be63fd
2 changed files with 211 additions and 59 deletions

View File

@ -1,3 +1,12 @@
Tue Oct 25 11:44:38 1994 Ian Lance Taylor <ian@sanguine.cygnus.com>
* linker.c (enum link_action): Add CIND.
(link_action): Change COMMON_ROW\indr from MDEF to CREF. Change
INDR_ROW\common from MDEF to CIND.
(_bfd_generic_link_add_one_symbol): In CREF case, handle an
existing symbol which is indirect rather than defined. Add new
CIND case.
Mon Oct 24 15:33:16 1994 Ian Lance Taylor <ian@sanguine.cygnus.com> Mon Oct 24 15:33:16 1994 Ian Lance Taylor <ian@sanguine.cygnus.com>
Change S-record backend to use multiple sections to handle gaps in Change S-record backend to use multiple sections to handle gaps in

View File

@ -1,5 +1,5 @@
/* linker.c -- BFD linker routines /* linker.c -- BFD linker routines
Copyright (C) 1993, 94 Free Software Foundation, Inc. Copyright (C) 1993, 1994 Free Software Foundation, Inc.
Written by Steve Chamberlain and Ian Lance Taylor, Cygnus Support Written by Steve Chamberlain and Ian Lance Taylor, Cygnus Support
This file is part of BFD, the Binary File Descriptor library. This file is part of BFD, the Binary File Descriptor library.
@ -427,6 +427,8 @@ static boolean generic_link_check_archive_element
static boolean generic_link_add_symbol_list static boolean generic_link_add_symbol_list
PARAMS ((bfd *, struct bfd_link_info *, bfd_size_type count, asymbol **, PARAMS ((bfd *, struct bfd_link_info *, bfd_size_type count, asymbol **,
boolean collect)); boolean collect));
static void set_symbol_from_hash
PARAMS ((asymbol *, struct bfd_link_hash_entry *));
static boolean generic_add_output_symbol static boolean generic_add_output_symbol
PARAMS ((bfd *, size_t *psymalloc, asymbol *)); PARAMS ((bfd *, size_t *psymalloc, asymbol *));
static boolean default_fill_link_order static boolean default_fill_link_order
@ -434,7 +436,7 @@ static boolean default_fill_link_order
struct bfd_link_order *)); struct bfd_link_order *));
static boolean default_indirect_link_order static boolean default_indirect_link_order
PARAMS ((bfd *, struct bfd_link_info *, asection *, PARAMS ((bfd *, struct bfd_link_info *, asection *,
struct bfd_link_order *)); struct bfd_link_order *, boolean));
/* The link hash table structure is defined in bfdlink.h. It provides /* The link hash table structure is defined in bfdlink.h. It provides
a base hash table which the backend specific hash tables are built a base hash table which the backend specific hash tables are built
@ -897,7 +899,10 @@ _bfd_generic_link_add_archive_symbols (abfd, info, checkfn)
l->next = NULL; l->next = NULL;
} }
pass = 1; /* The archive_pass field in the archive itself is used to
initialize PASS, sine we may search the same archive multiple
times. */
pass = abfd->archive_pass + 1;
/* New undefined symbols are added to the end of the list, so we /* New undefined symbols are added to the end of the list, so we
only need to look through it once. */ only need to look through it once. */
@ -987,6 +992,9 @@ _bfd_generic_link_add_archive_symbols (abfd, info, checkfn)
archive_hash_table_free (&arsym_hash); archive_hash_table_free (&arsym_hash);
/* Save PASS in case we are called again. */
abfd->archive_pass = pass;
return true; return true;
error_return: error_return:
@ -1089,6 +1097,8 @@ generic_link_check_archive_element (abfd, info, pneeded, collect)
if (h->type == bfd_link_hash_undefined) if (h->type == bfd_link_hash_undefined)
{ {
bfd *symbfd; bfd *symbfd;
bfd_vma size;
unsigned int power;
symbfd = h->u.undef.abfd; symbfd = h->u.undef.abfd;
if (symbfd == (bfd *) NULL) if (symbfd == (bfd *) NULL)
@ -1111,7 +1121,21 @@ generic_link_check_archive_element (abfd, info, pneeded, collect)
attached to symbfd to ensure that it is in a BFD which attached to symbfd to ensure that it is in a BFD which
will be linked in. */ will be linked in. */
h->type = bfd_link_hash_common; h->type = bfd_link_hash_common;
h->u.c.size = bfd_asymbol_value (p);
size = bfd_asymbol_value (p);
h->u.c.size = size;
if (h->u.c.size != size)
{
/* The size did not fit in the bitfield. */
bfd_set_error (bfd_error_bad_value);
return false;
}
power = bfd_log2 (size);
if (power > 4)
power = 4;
h->u.c.alignment_power = power;
if (p->section == bfd_com_section_ptr) if (p->section == bfd_com_section_ptr)
h->u.c.section = bfd_make_section_old_way (symbfd, "COMMON"); h->u.c.section = bfd_make_section_old_way (symbfd, "COMMON");
else else
@ -1218,8 +1242,10 @@ generic_link_add_symbol_list (abfd, info, symbol_count, symbols, collect)
/* Store a back pointer from the symbol to the hash /* Store a back pointer from the symbol to the hash
table entry for the benefit of relaxation code until table entry for the benefit of relaxation code until
it gets rewritten to not use asymbol structures. */ it gets rewritten to not use asymbol structures.
p->udata = (PTR) h; Setting this is also used to check whether these
symbols were set up by the generic linker. */
p->udata.p = (PTR) h;
} }
} }
} }
@ -1267,6 +1293,7 @@ enum link_action
MDEF, /* Multiple definition error. */ MDEF, /* Multiple definition error. */
MIND, /* Multiple indirect symbols. */ MIND, /* Multiple indirect symbols. */
IND, /* Make indirect symbol. */ IND, /* Make indirect symbol. */
CIND, /* Make indirect symbol from existing common symbol. */
SET, /* Add value to set. */ SET, /* Add value to set. */
MWARN, /* Make warning symbol. */ MWARN, /* Make warning symbol. */
WARN, /* Issue warning. */ WARN, /* Issue warning. */
@ -1286,8 +1313,8 @@ static const enum link_action link_action[8][7] =
/* UNDEFW_ROW */ {WEAK, WEAK, NOACT, REF, NOACT, REFC, WARNC }, /* UNDEFW_ROW */ {WEAK, WEAK, NOACT, REF, NOACT, REFC, WARNC },
/* DEF_ROW */ {DEF, DEF, DEF, MDEF, CDEF, MDEF, CYCLE }, /* DEF_ROW */ {DEF, DEF, DEF, MDEF, CDEF, MDEF, CYCLE },
/* DEFW_ROW */ {DEF, DEF, DEF, NOACT, NOACT, NOACT, CYCLE }, /* DEFW_ROW */ {DEF, DEF, DEF, NOACT, NOACT, NOACT, CYCLE },
/* COMMON_ROW */ {COM, COM, COM, CREF, BIG, MDEF, WARNC }, /* COMMON_ROW */ {COM, COM, COM, CREF, BIG, CREF, WARNC },
/* INDR_ROW */ {IND, IND, IND, MDEF, MDEF, MIND, CYCLE }, /* INDR_ROW */ {IND, IND, IND, MDEF, CIND, MIND, CYCLE },
/* WARN_ROW */ {MWARN, WARN, WARN, CWARN, WARN, CWARN, CYCLE }, /* WARN_ROW */ {MWARN, WARN, WARN, CWARN, WARN, CWARN, CYCLE },
/* SET_ROW */ {SET, SET, SET, SET, SET, CYCLE, CYCLE } /* SET_ROW */ {SET, SET, SET, SET, SET, CYCLE, CYCLE }
}; };
@ -1491,6 +1518,34 @@ _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value,
bfd_link_add_undef (info->hash, h); bfd_link_add_undef (info->hash, h);
h->type = bfd_link_hash_common; h->type = bfd_link_hash_common;
h->u.c.size = value; h->u.c.size = value;
if (h->u.c.size != value)
{
/* The size did not fit in the bitfield. */
bfd_set_error (bfd_error_bad_value);
return false;
}
/* Select a default alignment based on the size. This may
be overridden by the caller. */
{
unsigned int power;
power = bfd_log2 (value);
if (power > 4)
power = 4;
h->u.c.alignment_power = power;
}
/* The section of a common symbol is only used if the common
symbol is actually allocated. It basically provides a
hook for the linker script to decide which output section
the common symbols should be put in. In most cases, the
section of a common symbol will be bfd_com_section_ptr,
the code here will choose a common symbol section named
"COMMON", and the linker script will contain *(COMMON) in
the appropriate place. A few targets use separate common
sections for small symbols, and they require special
handling. */
if (section == bfd_com_section_ptr) if (section == bfd_com_section_ptr)
{ {
h->u.c.section = bfd_make_section_old_way (abfd, "COMMON"); h->u.c.section = bfd_make_section_old_way (abfd, "COMMON");
@ -1522,18 +1577,37 @@ _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value,
abfd, bfd_link_hash_common, value))) abfd, bfd_link_hash_common, value)))
return false; return false;
if (value > h->u.c.size) if (value > h->u.c.size)
h->u.c.size = value; {
unsigned int power;
h->u.c.size = value;
/* Select a default alignment based on the size. This may
be overridden by the caller. */
power = bfd_log2 (value);
if (power > 4)
power = 4;
h->u.c.alignment_power = power;
}
break; break;
case CREF: case CREF:
/* We have found a common definition for a symbol which was {
already defined. */ bfd *obfd;
BFD_ASSERT (h->type == bfd_link_hash_defined);
if (! ((*info->callbacks->multiple_common) /* We have found a common definition for a symbol which
(info, name, was already defined. FIXME: It would nice if we could
h->u.def.section->owner, bfd_link_hash_defined, (bfd_vma) 0, report the BFD which defined an indirect symbol, but we
abfd, bfd_link_hash_common, value))) don't have anywhere to store the information. */
return false; if (h->type == bfd_link_hash_defined)
obfd = h->u.def.section->owner;
else
obfd = NULL;
if (! ((*info->callbacks->multiple_common)
(info, name, obfd, h->type, (bfd_vma) 0,
abfd, bfd_link_hash_common, value)))
return false;
}
break; break;
case MIND: case MIND:
@ -1573,6 +1647,15 @@ _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value,
} }
break; break;
case CIND:
/* Create an indirect symbol from an existing common symbol. */
BFD_ASSERT (h->type == bfd_link_hash_common);
if (! ((*info->callbacks->multiple_common)
(info, name,
h->u.c.section->owner, bfd_link_hash_common, h->u.c.size,
abfd, bfd_link_hash_indirect, (bfd_vma) 0)))
return false;
/* Fall through. */
case IND: case IND:
/* Create an indirect symbol. */ /* Create an indirect symbol. */
{ {
@ -1805,6 +1888,10 @@ _bfd_generic_final_link (abfd, info)
if (! _bfd_generic_reloc_link_order (abfd, info, o, p)) if (! _bfd_generic_reloc_link_order (abfd, info, o, p))
return false; return false;
break; break;
case bfd_indirect_link_order:
if (! default_indirect_link_order (abfd, info, o, p, true))
return false;
break;
default: default:
if (! _bfd_default_link_order (abfd, info, o, p)) if (! _bfd_default_link_order (abfd, info, o, p))
return false; return false;
@ -2045,6 +2132,50 @@ _bfd_generic_link_output_symbols (output_bfd, input_bfd, info, psymalloc)
return true; return true;
} }
/* Set the section and value of a generic BFD symbol based on a linker
hash table entry. */
static void
set_symbol_from_hash (sym, h)
asymbol *sym;
struct bfd_link_hash_entry *h;
{
switch (h->type)
{
default:
case bfd_link_hash_new:
abort ();
case bfd_link_hash_undefined:
sym->section = bfd_und_section_ptr;
sym->value = 0;
break;
case bfd_link_hash_weak:
sym->section = bfd_und_section_ptr;
sym->value = 0;
sym->flags |= BSF_WEAK;
break;
case bfd_link_hash_defined:
sym->section = h->u.def.section;
sym->value = h->u.def.value;
break;
case bfd_link_hash_common:
sym->value = h->u.c.size;
if (sym->section == NULL)
sym->section = bfd_com_section_ptr;
else if (! bfd_is_com_section (sym->section))
{
BFD_ASSERT (bfd_is_und_section (sym->section));
sym->section = bfd_com_section_ptr;
}
/* Do not set the section; see _bfd_generic_link_output_symbols. */
break;
case bfd_link_hash_indirect:
case bfd_link_hash_warning:
/* FIXME: What should we do here? */
break;
}
}
/* Write out a global symbol, if it hasn't already been written out. /* Write out a global symbol, if it hasn't already been written out.
This is called for each symbol in the hash table. */ This is called for each symbol in the hash table. */
@ -2082,40 +2213,7 @@ _bfd_generic_link_write_global_symbol (h, data)
sym->flags = 0; sym->flags = 0;
} }
switch (h->root.type) set_symbol_from_hash (sym, &h->root);
{
default:
case bfd_link_hash_new:
abort ();
case bfd_link_hash_undefined:
sym->section = bfd_und_section_ptr;
sym->value = 0;
break;
case bfd_link_hash_weak:
sym->section = bfd_und_section_ptr;
sym->value = 0;
sym->flags |= BSF_WEAK;
break;
case bfd_link_hash_defined:
sym->section = h->root.u.def.section;
sym->value = h->root.u.def.value;
break;
case bfd_link_hash_common:
sym->value = h->root.u.c.size;
if (sym->section == NULL)
sym->section = bfd_com_section_ptr;
else if (! bfd_is_com_section (sym->section))
{
BFD_ASSERT (bfd_is_und_section (sym->section));
sym->section = bfd_com_section_ptr;
}
/* Do not set the section; see _bfd_generic_link_output_symbols. */
break;
case bfd_link_hash_indirect:
case bfd_link_hash_warning:
/* FIXME: What should we do here? */
break;
}
sym->flags |= BSF_GLOBAL; sym->flags |= BSF_GLOBAL;
@ -2289,7 +2387,8 @@ _bfd_default_link_order (abfd, info, sec, link_order)
default: default:
abort (); abort ();
case bfd_indirect_link_order: case bfd_indirect_link_order:
return default_indirect_link_order (abfd, info, sec, link_order); return default_indirect_link_order (abfd, info, sec, link_order,
false);
case bfd_fill_link_order: case bfd_fill_link_order:
return default_fill_link_order (abfd, info, sec, link_order); return default_fill_link_order (abfd, info, sec, link_order);
case bfd_data_link_order: case bfd_data_link_order:
@ -2341,11 +2440,13 @@ default_fill_link_order (abfd, info, sec, link_order)
/* Default routine to handle a bfd_indirect_link_order. */ /* Default routine to handle a bfd_indirect_link_order. */
static boolean static boolean
default_indirect_link_order (output_bfd, info, output_section, link_order) default_indirect_link_order (output_bfd, info, output_section, link_order,
generic_linker)
bfd *output_bfd; bfd *output_bfd;
struct bfd_link_info *info; struct bfd_link_info *info;
asection *output_section; asection *output_section;
struct bfd_link_order *link_order; struct bfd_link_order *link_order;
boolean generic_linker;
{ {
asection *input_section; asection *input_section;
bfd *input_bfd; bfd *input_bfd;
@ -2376,12 +2477,54 @@ default_indirect_link_order (output_bfd, info, output_section, link_order)
abort (); abort ();
} }
/* Get the canonical symbols. The generic linker will always have if (! generic_linker)
retrieved them by this point, but we may be being called by a {
specific linker when linking different types of object files asymbol **sympp;
together. */ asymbol **symppend;
if (! generic_link_read_symbols (input_bfd))
return false; /* Get the canonical symbols. The generic linker will always
have retrieved them by this point, but we are being called by
a specific linker, presumably because we are linking
different types of object files together. */
if (! generic_link_read_symbols (input_bfd))
return false;
/* Since we have been called by a specific linker, rather than
the generic linker, the values of the symbols will not be
right. They will be the values as seen in the input file,
not the values of the final link. We need to fix them up
before we can relocate the section. */
sympp = _bfd_generic_link_get_symbols (input_bfd);
symppend = sympp + _bfd_generic_link_get_symcount (input_bfd);
for (; sympp < symppend; sympp++)
{
asymbol *sym;
struct bfd_link_hash_entry *h;
sym = *sympp;
if ((sym->flags & (BSF_INDIRECT
| BSF_WARNING
| BSF_GLOBAL
| BSF_CONSTRUCTOR
| BSF_WEAK)) != 0
|| bfd_is_und_section (bfd_get_section (sym))
|| bfd_is_com_section (bfd_get_section (sym))
|| bfd_is_ind_section (bfd_get_section (sym)))
{
/* sym->udata may have been set by
generic_link_add_symbol_list. */
if (sym->udata.p != NULL)
h = (struct bfd_link_hash_entry *) sym->udata.p;
else
h = bfd_link_hash_lookup (info->hash,
bfd_asymbol_name (sym),
false, false, true);
if (h != NULL)
set_symbol_from_hash (sym, h);
}
}
}
/* Get and relocate the section contents. */ /* Get and relocate the section contents. */
contents = (bfd_byte *) malloc (bfd_section_size (input_bfd, input_section)); contents = (bfd_byte *) malloc (bfd_section_size (input_bfd, input_section));