* xcofflink.c: More improvements, mostly to fix handling of

constructors and a few other special cases.
	* coff-rs6000.c (rs6000coff_vec): Set symbol_leading_char back to
	zero, reverting yesterday's change.
	* bfd-in.h (bfd_xcoff_link_record_set): Declare.
	(bfd_xcoff_link_count_reloc): Declare.
	(bfd_xcoff_record_link_assignment): Declare.
	* bfd-in2.h: Rebuild.
This commit is contained in:
Ian Lance Taylor 1995-10-27 22:20:19 +00:00
parent 0fb3e100cb
commit 2d7de17d61
5 changed files with 320 additions and 60 deletions

View File

@ -1,3 +1,14 @@
Fri Oct 27 18:14:39 1995 Ian Lance Taylor <ian@cygnus.com>
* xcofflink.c: More improvements, mostly to fix handling of
constructors and a few other special cases.
* coff-rs6000.c (rs6000coff_vec): Set symbol_leading_char back to
zero, reverting yesterday's change.
* bfd-in.h (bfd_xcoff_link_record_set): Declare.
(bfd_xcoff_link_count_reloc): Declare.
(bfd_xcoff_record_link_assignment): Declare.
* bfd-in2.h: Rebuild.
start-sanitize-gm
Fri Oct 27 09:41:51 1995 Stu Grossman (grossman@cygnus.com)

View File

@ -602,12 +602,19 @@ extern boolean bfd_linux_size_dynamic_sections
/* XCOFF support routines for the linker. */
extern boolean bfd_xcoff_link_record_set
PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *,
bfd_size_type));
extern boolean bfd_xcoff_import_symbol
PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *,
bfd_vma, const char *, const char *, const char *));
extern boolean bfd_xcoff_export_symbol
PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *,
boolean));
extern boolean bfd_xcoff_link_count_reloc
PARAMS ((bfd *, struct bfd_link_info *, const char *));
extern boolean bfd_xcoff_record_link_assignment
PARAMS ((bfd *, struct bfd_link_info *, const char *));
extern boolean bfd_xcoff_size_dynamic_sections
PARAMS ((bfd *, struct bfd_link_info *, const char *, const char *,
unsigned long, unsigned long, unsigned long, boolean,

View File

@ -602,12 +602,19 @@ extern boolean bfd_linux_size_dynamic_sections
/* XCOFF support routines for the linker. */
extern boolean bfd_xcoff_link_record_set
PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *,
bfd_size_type));
extern boolean bfd_xcoff_import_symbol
PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *,
bfd_vma, const char *, const char *, const char *));
extern boolean bfd_xcoff_export_symbol
PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *,
boolean));
extern boolean bfd_xcoff_link_count_reloc
PARAMS ((bfd *, struct bfd_link_info *, const char *));
extern boolean bfd_xcoff_record_link_assignment
PARAMS ((bfd *, struct bfd_link_info *, const char *));
extern boolean bfd_xcoff_size_dynamic_sections
PARAMS ((bfd *, struct bfd_link_info *, const char *, const char *,
unsigned long, unsigned long, unsigned long, boolean,

View File

@ -1353,8 +1353,7 @@ const bfd_target rs6000coff_vec =
HAS_SYMS | HAS_LOCALS | WP_TEXT),
(SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
/* Making the leading_char a period should make for nicer messages. */
'.', /* leading char */
0, /* leading char */
'/', /* ar_pad_char */
15, /* ar_max_namelen??? FIXMEmgo */

View File

@ -286,6 +286,8 @@ struct xcoff_link_hash_entry
#define XCOFF_BUILT_LDSYM (01000)
/* Symbol is mentioned by a section which was not garbage collected. */
#define XCOFF_MARK (02000)
/* Symbol size is recorded in size_list list from hash table. */
#define XCOFF_HAS_SIZE (04000)
/* The storage mapping class. */
unsigned char smclas;
@ -333,6 +335,14 @@ struct xcoff_link_hash_table
/* Whether garbage collection was done. */
boolean gc;
/* A linked list of symbols for which we have size information. */
struct xcoff_link_size_list
{
struct xcoff_link_size_list *next;
struct xcoff_link_hash_entry *h;
bfd_size_type size;
} *size_list;
};
/* Information we keep for each section in the output file during the
@ -345,6 +355,16 @@ struct xcoff_link_section_info
/* For each reloc against a global symbol whose index was not known
when the reloc was handled, the global hash table entry. */
struct xcoff_link_hash_entry **rel_hashes;
/* If there is a TOC relative reloc against a global symbol, and the
index of the TOC symbol is not known when the reloc was handled,
an entry is added to this linked list. This is not an array,
like rel_hashes, because this case is quite uncommon. */
struct xcoff_toc_rel_hash
{
struct xcoff_toc_rel_hash *next;
struct xcoff_link_hash_entry *h;
struct internal_reloc *rel;
} *toc_rel_hashes;
};
/* Information that we pass around while doing the final link step. */
@ -1564,7 +1584,8 @@ xcoff_link_add_symbols (abfd, info)
flag = XCOFF_DEF_REGULAR;
(*sym_hash)->flags |= flag;
if ((*sym_hash)->smclas == XMC_UA)
if ((*sym_hash)->smclas == XMC_UA
|| flag == XCOFF_DEF_REGULAR)
(*sym_hash)->smclas = aux.x_csect.x_smclas;
}
}
@ -1850,6 +1871,40 @@ xcoff_link_add_dynamic_symbols (abfd, info)
/* Routines that are called after all the input files have been
handled, but before the sections are laid out in memory. */
/* Record the number of elements in a set. This is used to output the
correct csect length. */
boolean
bfd_xcoff_link_record_set (output_bfd, info, harg, size)
bfd *output_bfd;
struct bfd_link_info *info;
struct bfd_link_hash_entry *harg;
bfd_size_type size;
{
struct xcoff_link_hash_entry *h = (struct xcoff_link_hash_entry *) harg;
struct xcoff_link_size_list *n;
/* This will hardly ever be called. I don't want to burn four bytes
per global symbol, so instead the size is kept on a linked list
attached to the hash table. */
n = ((struct xcoff_link_size_list *)
bfd_alloc (output_bfd, sizeof (struct xcoff_link_size_list)));
if (n == NULL)
{
bfd_set_error (bfd_error_no_memory);
return false;
}
n->next = xcoff_hash_table (info)->size_list;
n->h = h;
n->size = size;
xcoff_hash_table (info)->size_list = n;
h->flags |= XCOFF_HAS_SIZE;
return true;
}
/* Import a symbol. */
boolean
@ -1956,6 +2011,79 @@ bfd_xcoff_export_symbol (output_bfd, info, harg, syscall)
return true;
}
/* Count a reloc against a symbol. This is called for relocs
generated by the linker script, typically for global constructors
and destructors. */
boolean
bfd_xcoff_link_count_reloc (output_bfd, info, name)
bfd *output_bfd;
struct bfd_link_info *info;
const char *name;
{
struct xcoff_link_hash_entry *h;
h = xcoff_link_hash_lookup (xcoff_hash_table (info), name, false, false,
false);
if (h == NULL)
{
(*_bfd_error_handler) ("%s: no such symbol", name);
bfd_set_error (bfd_error_no_symbols);
return false;
}
h->flags |= XCOFF_REF_REGULAR | XCOFF_LDREL;
++xcoff_hash_table (info)->ldrel_count;
/* Mark the symbol to avoid garbage collection. */
if ((h->flags & XCOFF_MARK) == 0)
{
h->flags |= XCOFF_MARK;
if (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
{
asection *hsec;
hsec = h->root.u.def.section;
if ((hsec->flags & SEC_MARK) == 0)
{
if (! xcoff_mark (info, hsec))
return false;
}
}
if (h->toc_section != NULL
&& (h->toc_section->flags & SEC_MARK) == 0)
{
if (! xcoff_mark (info, h->toc_section))
return false;
}
}
return true;
}
/* This function is called for each symbol to which the linker script
assigns a value. */
boolean
bfd_xcoff_record_link_assignment (output_bfd, info, name)
bfd *output_bfd;
struct bfd_link_info *info;
const char *name;
{
struct xcoff_link_hash_entry *h;
h = xcoff_link_hash_lookup (xcoff_hash_table (info), name, true, true,
false);
if (h == NULL)
return false;
h->flags |= XCOFF_DEF_REGULAR;
return true;
}
/* This structure is used to pass information through
xcoff_link_hash_traverse. */
@ -2904,6 +3032,7 @@ _bfd_xcoff_bfd_final_link (abfd, info)
{
finfo.section_info[i].relocs = NULL;
finfo.section_info[i].rel_hashes = NULL;
finfo.section_info[i].toc_rel_hashes = NULL;
}
}
@ -3107,6 +3236,7 @@ _bfd_xcoff_bfd_final_link (abfd, info)
struct internal_reloc *irel;
struct internal_reloc *irelend;
struct xcoff_link_hash_entry **rel_hash;
struct xcoff_toc_rel_hash *toc_rel_hash;
bfd_byte *erel;
if (o->reloc_count == 0)
@ -3131,6 +3261,21 @@ _bfd_xcoff_bfd_final_link (abfd, info)
}
}
for (toc_rel_hash = finfo.section_info[o->target_index].toc_rel_hashes;
toc_rel_hash != NULL;
toc_rel_hash = toc_rel_hash->next)
{
if (toc_rel_hash->h->u.toc_indx < 0)
{
if (! ((*info->callbacks->unattached_reloc)
(info, toc_rel_hash->h->root.root.string,
(bfd *) NULL, o, toc_rel_hash->rel->r_vaddr)))
goto error_return;
toc_rel_hash->h->u.toc_indx = 0;
}
toc_rel_hash->rel->r_symndx = toc_rel_hash->h->u.toc_indx;
}
/* XCOFF requires that the relocs be sorted by address. We tend
to produce them in the order in which their containing csects
appear in the symbol table, which is not necessarily by
@ -4082,18 +4227,27 @@ xcoff_link_input_bfd (finfo, input_bfd)
not the symbol itself. */
BFD_ASSERT (h->toc_section != NULL);
BFD_ASSERT ((h->flags & XCOFF_SET_TOC) == 0);
if (h->u.toc_indx == -1)
if (h->u.toc_indx != -1)
irel->r_symndx = h->u.toc_indx;
else
{
/* We could handle this case if we had to,
but I don't think it can arise. */
(*_bfd_error_handler)
("%s: unattached TOC reloc against `%s'",
bfd_get_filename (input_bfd),
h->root.root.string);
bfd_set_error (bfd_error_bad_value);
return false;
struct xcoff_toc_rel_hash *n;
struct xcoff_link_section_info *si;
n = ((struct xcoff_toc_rel_hash *)
bfd_alloc (finfo->output_bfd,
sizeof (struct xcoff_toc_rel_hash)));
if (n == NULL)
{
bfd_set_error (bfd_error_no_memory);
return false;
}
si = finfo->section_info + target_index;
n->next = si->toc_rel_hashes;
n->h = h;
n->rel = irel;
si->toc_rel_hashes = n;
}
irel->r_symndx = h->u.toc_indx;
}
else if (h != NULL)
{
@ -4493,13 +4647,37 @@ xcoff_write_global_symbol (h, p)
else if (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
{
struct xcoff_link_size_list *l;
isym.n_value = (h->root.u.def.section->output_section->vma
+ h->root.u.def.section->output_offset
+ h->root.u.def.value);
isym.n_scnum = h->root.u.def.section->output_section->target_index;
isym.n_sclass = C_HIDEXT;
aux.x_csect.x_smtyp = XTY_SD;
/* I don't know what the csect length should be in this case. */
if ((h->flags & XCOFF_HAS_SIZE) != 0)
{
for (l = xcoff_hash_table (finfo->info)->size_list;
l != NULL;
l = l->next)
{
if (l->h == h)
{
aux.x_csect.x_scnlen.l = l->size;
break;
}
}
}
}
else if (h->root.type == bfd_link_hash_common)
{
isym.n_value = (h->root.u.c.p->section->output_section->vma
+ h->root.u.c.p->section->output_offset);
isym.n_scnum = h->root.u.c.p->section->output_section->target_index;
isym.n_sclass = C_EXT;
aux.x_csect.x_smtyp = XTY_CM;
aux.x_csect.x_scnlen.l = h->root.u.c.size;
}
else
abort ();
@ -4559,8 +4737,22 @@ xcoff_reloc_link_order (output_bfd, finfo, output_section, link_order)
struct bfd_link_order *link_order;
{
reloc_howto_type *howto;
struct xcoff_link_hash_entry *h;
asection *hsec;
bfd_vma hval;
bfd_vma addend;
struct internal_reloc *irel;
struct xcoff_link_hash_entry **rel_hash_ptr;
struct internal_ldrel ldrel;
if (link_order->type == bfd_section_reloc_link_order)
{
/* We need to somehow locate a symbol in the right section. The
symbol must either have a value of zero, or we must adjust
the addend by the value of the symbol. FIXME: Write this
when we need it. The old linker couldn't handle this anyhow. */
abort ();
}
howto = bfd_reloc_type_lookup (output_bfd, link_order->u.reloc.p->reloc);
if (howto == NULL)
@ -4569,7 +4761,42 @@ xcoff_reloc_link_order (output_bfd, finfo, output_section, link_order)
return false;
}
if (link_order->u.reloc.p->addend != 0)
h = xcoff_link_hash_lookup (xcoff_hash_table (finfo->info),
link_order->u.reloc.p->u.name,
false, false, true);
if (h == NULL)
{
if (! ((*finfo->info->callbacks->unattached_reloc)
(finfo->info, link_order->u.reloc.p->u.name, (bfd *) NULL,
(asection *) NULL, (bfd_vma) 0)))
return false;
return true;
}
if (h->root.type == bfd_link_hash_common)
{
hsec = h->root.u.c.p->section;
hval = 0;
}
else if (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
{
hsec = h->root.u.def.section;
hval = h->root.u.def.value;
}
else
{
hsec = NULL;
hval = 0;
}
addend = link_order->u.reloc.p->addend;
if (hsec != NULL)
addend += (hsec->output_section->vma
+ hsec->output_offset
+ hval);
if (addend != 0)
{
bfd_size_type size;
bfd_byte *buf;
@ -4584,8 +4811,7 @@ xcoff_reloc_link_order (output_bfd, finfo, output_section, link_order)
return false;
}
rstat = _bfd_relocate_contents (howto, output_bfd,
link_order->u.reloc.p->addend, buf);
rstat = _bfd_relocate_contents (howto, output_bfd, addend, buf);
switch (rstat)
{
case bfd_reloc_ok:
@ -4595,13 +4821,9 @@ xcoff_reloc_link_order (output_bfd, finfo, output_section, link_order)
abort ();
case bfd_reloc_overflow:
if (! ((*finfo->info->callbacks->reloc_overflow)
(finfo->info,
(link_order->type == bfd_section_reloc_link_order
? bfd_section_name (output_bfd,
link_order->u.reloc.p->u.section)
: link_order->u.reloc.p->u.name),
howto->name, link_order->u.reloc.p->addend,
(bfd *) NULL, (asection *) NULL, (bfd_vma) 0)))
(finfo->info, link_order->u.reloc.p->u.name,
howto->name, addend, (bfd *) NULL, (asection *) NULL,
(bfd_vma) 0)))
{
free (buf);
return false;
@ -4628,44 +4850,14 @@ xcoff_reloc_link_order (output_bfd, finfo, output_section, link_order)
irel->r_vaddr = output_section->vma + link_order->offset;
if (link_order->type == bfd_section_reloc_link_order)
{
/* We need to somehow locate a symbol in the right section. The
symbol must either have a value of zero, or we must adjust
the addend by the value of the symbol. FIXME: Write this
when we need it. The old linker couldn't handle this anyhow. */
abort ();
*rel_hash_ptr = NULL;
irel->r_symndx = 0;
}
if (h->indx >= 0)
irel->r_symndx = h->indx;
else
{
struct xcoff_link_hash_entry *h;
h = xcoff_link_hash_lookup (xcoff_hash_table (finfo->info),
link_order->u.reloc.p->u.name,
false, false, true);
if (h != NULL)
{
if (h->indx >= 0)
irel->r_symndx = h->indx;
else
{
/* Set the index to -2 to force this symbol to get
written out. */
h->indx = -2;
*rel_hash_ptr = h;
irel->r_symndx = 0;
}
}
else
{
if (! ((*finfo->info->callbacks->unattached_reloc)
(finfo->info, link_order->u.reloc.p->u.name, (bfd *) NULL,
(asection *) NULL, (bfd_vma) 0)))
return false;
irel->r_symndx = 0;
}
/* Set the index to -2 to force this symbol to get written out. */
h->indx = -2;
*rel_hash_ptr = h;
irel->r_symndx = 0;
}
irel->r_type = howto->type;
@ -4675,6 +4867,50 @@ xcoff_reloc_link_order (output_bfd, finfo, output_section, link_order)
++output_section->reloc_count;
/* Now output the reloc to the .loader section. */
ldrel.l_vaddr = irel->r_vaddr;
if (hsec != NULL)
{
const char *secname;
secname = hsec->output_section->name;
if (strcmp (secname, ".text") == 0)
ldrel.l_symndx = 0;
else if (strcmp (secname, ".data") == 0)
ldrel.l_symndx = 1;
else if (strcmp (secname, ".bss") == 0)
ldrel.l_symndx = 2;
else
{
(*_bfd_error_handler)
("%s: loader reloc in unrecognized section `%s'",
bfd_get_filename (output_bfd), secname);
bfd_set_error (bfd_error_nonrepresentable_section);
return false;
}
}
else
{
if (h->ldindx < 0)
{
(*_bfd_error_handler)
("%s: `%s' in loader reloc but not loader sym",
bfd_get_filename (output_bfd),
h->root.root.string);
bfd_set_error (bfd_error_bad_value);
return false;
}
ldrel.l_symndx = h->ldindx;
}
ldrel.l_rtype = (irel->r_size << 8) | irel->r_type;
ldrel.l_rsecnm = output_section->target_index;
xcoff_swap_ldrel_out (output_bfd, &ldrel, finfo->ldrel);
++finfo->ldrel;
return true;
}