aboutsummaryrefslogtreecommitdiff
path: root/bfd/xcofflink.c
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@airs.com>1995-10-27 22:20:19 +0000
committerIan Lance Taylor <ian@airs.com>1995-10-27 22:20:19 +0000
commit2d7de17d6167ef2c7240a6886541a9e0031ed798 (patch)
treec8048a11ea41544a629a277b71bbe9118957afcc /bfd/xcofflink.c
parent0fb3e100cb114c5c9f3b56374e8a8e94aa5b4460 (diff)
downloadfsf-binutils-gdb-2d7de17d6167ef2c7240a6886541a9e0031ed798.zip
fsf-binutils-gdb-2d7de17d6167ef2c7240a6886541a9e0031ed798.tar.gz
fsf-binutils-gdb-2d7de17d6167ef2c7240a6886541a9e0031ed798.tar.bz2
* 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.
Diffstat (limited to 'bfd/xcofflink.c')
-rw-r--r--bfd/xcofflink.c350
1 files changed, 293 insertions, 57 deletions
diff --git a/bfd/xcofflink.c b/bfd/xcofflink.c
index 843dc06..9674563 100644
--- a/bfd/xcofflink.c
+++ b/bfd/xcofflink.c
@@ -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,52 +4850,66 @@ 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)
+ if (h->indx >= 0)
+ irel->r_symndx = h->indx;
+ else
{
- /* 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;
+ /* 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
+
+ irel->r_type = howto->type;
+ irel->r_size = howto->bitsize - 1;
+ if (howto->complain_on_overflow == complain_overflow_signed)
+ irel->r_size |= 0x80;
+
+ ++output_section->reloc_count;
+
+ /* Now output the reloc to the .loader section. */
+
+ ldrel.l_vaddr = irel->r_vaddr;
+
+ if (hsec != NULL)
{
- struct xcoff_link_hash_entry *h;
+ const char *secname;
+
+ secname = hsec->output_section->name;
- h = xcoff_link_hash_lookup (xcoff_hash_table (finfo->info),
- link_order->u.reloc.p->u.name,
- false, false, true);
- if (h != NULL)
+ 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
{
- 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;
- }
+ (*_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
+ }
+ else
+ {
+ if (h->ldindx < 0)
{
- 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;
+ (*_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;
}
- irel->r_type = howto->type;
- irel->r_size = howto->bitsize - 1;
- if (howto->complain_on_overflow == complain_overflow_signed)
- irel->r_size |= 0x80;
-
- ++output_section->reloc_count;
+ 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;
}