aboutsummaryrefslogtreecommitdiff
path: root/bfd/xcofflink.c
diff options
context:
space:
mode:
Diffstat (limited to 'bfd/xcofflink.c')
-rw-r--r--bfd/xcofflink.c446
1 files changed, 239 insertions, 207 deletions
diff --git a/bfd/xcofflink.c b/bfd/xcofflink.c
index 0a38ac3..d651e3a 100644
--- a/bfd/xcofflink.c
+++ b/bfd/xcofflink.c
@@ -1845,19 +1845,16 @@ xcoff_link_add_symbols (bfd *abfd, struct bfd_link_info *info)
goto error_return;
}
- /* We identify all symbols which are called, so that we
- can create glue code for calls to functions imported
- from dynamic objects. */
+ /* We identify all function symbols that are the target
+ of a relocation, so that we can create glue code for
+ functions imported from dynamic objects. */
if (info->output_bfd->xvec == abfd->xvec
&& *rel_csect != bfd_und_section_ptr
- && (rel->r_type == R_BR
- || rel->r_type == R_RBR)
&& obj_xcoff_sym_hashes (abfd)[rel->r_symndx] != NULL)
{
struct xcoff_link_hash_entry *h;
h = obj_xcoff_sym_hashes (abfd)[rel->r_symndx];
- h->flags |= XCOFF_CALLED;
/* If the symbol name starts with a period, it is
the code of a function. If the symbol is
currently undefined, then add an undefined symbol
@@ -1890,11 +1887,12 @@ xcoff_link_add_symbols (bfd *abfd, struct bfd_link_info *info)
hds = (struct xcoff_link_hash_entry *) bh;
}
hds->flags |= XCOFF_DESCRIPTOR;
- BFD_ASSERT ((hds->flags & XCOFF_CALLED) == 0
- && (h->flags & XCOFF_DESCRIPTOR) == 0);
+ BFD_ASSERT ((h->flags & XCOFF_DESCRIPTOR) == 0);
hds->descriptor = h;
h->descriptor = hds;
}
+ if (h->root.root.string[0] == '.')
+ h->flags |= XCOFF_CALLED;
}
}
@@ -2203,6 +2201,94 @@ _bfd_xcoff_bfd_link_add_symbols (bfd *abfd, struct bfd_link_info *info)
}
}
+/* If symbol H has not been interpreted as a function descriptor,
+ see whether it should be. Set up its descriptor information if so. */
+
+static bfd_boolean
+xcoff_find_function (struct bfd_link_info *info,
+ struct xcoff_link_hash_entry *h)
+{
+ if ((h->flags & XCOFF_DESCRIPTOR) == 0
+ && h->root.root.string[0] != '.')
+ {
+ char *fnname;
+ struct xcoff_link_hash_entry *hfn;
+ bfd_size_type amt;
+
+ amt = strlen (h->root.root.string) + 2;
+ fnname = bfd_malloc (amt);
+ if (fnname == NULL)
+ return FALSE;
+ fnname[0] = '.';
+ strcpy (fnname + 1, h->root.root.string);
+ hfn = xcoff_link_hash_lookup (xcoff_hash_table (info),
+ fnname, FALSE, FALSE, TRUE);
+ free (fnname);
+ if (hfn != NULL
+ && hfn->smclas == XMC_PR
+ && (hfn->root.type == bfd_link_hash_defined
+ || hfn->root.type == bfd_link_hash_defweak))
+ {
+ h->flags |= XCOFF_DESCRIPTOR;
+ h->descriptor = hfn;
+ hfn->descriptor = h;
+ }
+ }
+ return TRUE;
+}
+
+/* H is an imported symbol. Set the import module's path, file and member
+ to IMPATH, IMPFILE and IMPMEMBER respectively. All three are null if
+ no specific import module is specified. */
+
+static bfd_boolean
+xcoff_set_import_path (struct bfd_link_info *info,
+ struct xcoff_link_hash_entry *h,
+ const char *imppath, const char *impfile,
+ const char *impmember)
+{
+ unsigned int c;
+ struct xcoff_import_file **pp;
+
+ /* We overload the ldindx field to hold the l_ifile value for this
+ symbol. */
+ BFD_ASSERT (h->ldsym == NULL);
+ BFD_ASSERT ((h->flags & XCOFF_BUILT_LDSYM) == 0);
+ if (imppath == NULL)
+ h->ldindx = -1;
+ else
+ {
+ /* We start c at 1 because the first entry in the import list is
+ reserved for the library search path. */
+ for (pp = &xcoff_hash_table (info)->imports, c = 1;
+ *pp != NULL;
+ pp = &(*pp)->next, ++c)
+ {
+ if (strcmp ((*pp)->path, imppath) == 0
+ && strcmp ((*pp)->file, impfile) == 0
+ && strcmp ((*pp)->member, impmember) == 0)
+ break;
+ }
+
+ if (*pp == NULL)
+ {
+ struct xcoff_import_file *n;
+ bfd_size_type amt = sizeof (* n);
+
+ n = bfd_alloc (info->output_bfd, amt);
+ if (n == NULL)
+ return FALSE;
+ n->next = NULL;
+ n->path = imppath;
+ n->file = impfile;
+ n->member = impmember;
+ *pp = n;
+ }
+ h->ldindx = c;
+ }
+ return TRUE;
+}
+
/* Mark a symbol as not being garbage, including the section in which
it is defined. */
@@ -2213,6 +2299,136 @@ xcoff_mark_symbol (struct bfd_link_info *info, struct xcoff_link_hash_entry *h)
return TRUE;
h->flags |= XCOFF_MARK;
+
+ /* If we're marking an undefined symbol, try find some way of
+ defining it. */
+ if (!info->relocatable
+ && (h->flags & XCOFF_IMPORT) == 0
+ && (h->flags & XCOFF_DEF_REGULAR) == 0
+ && (h->root.type == bfd_link_hash_undefined
+ || h->root.type == bfd_link_hash_undefweak))
+ {
+ /* First check whether this symbol can be interpreted as an
+ undefined function descriptor for a defined function symbol. */
+ if (!xcoff_find_function (info, h))
+ return FALSE;
+
+ if ((h->flags & XCOFF_DESCRIPTOR) != 0
+ && (h->descriptor->root.type == bfd_link_hash_defined
+ || h->descriptor->root.type == bfd_link_hash_defweak))
+ {
+ /* This is a descriptor for a defined symbol, but the input
+ objects have not defined the descriptor itself. Fill in
+ the definition automatically.
+
+ Note that we do this even if we found a dynamic definition
+ of H. The local function definition logically overrides
+ the dynamic one. */
+ asection *sec;
+
+ sec = xcoff_hash_table (info)->descriptor_section;
+ h->root.type = bfd_link_hash_defined;
+ h->root.u.def.section = sec;
+ h->root.u.def.value = sec->size;
+ h->smclas = XMC_DS;
+ h->flags |= XCOFF_DEF_REGULAR;
+
+ /* The size of the function descriptor depends on whether this
+ is xcoff32 (12) or xcoff64 (24). */
+ sec->size += bfd_xcoff_function_descriptor_size (sec->owner);
+
+ /* A function descriptor uses two relocs: one for the
+ associated code, and one for the TOC address. */
+ xcoff_hash_table (info)->ldrel_count += 2;
+ sec->reloc_count += 2;
+
+ /* Mark the function itself. */
+ if (!xcoff_mark_symbol (info, h->descriptor))
+ return FALSE;
+
+ /* We handle writing out the contents of the descriptor in
+ xcoff_write_global_symbol. */
+ }
+ else if ((h->flags & XCOFF_CALLED) != 0)
+ {
+ /* This is a function symbol for which we need to create
+ linkage code. */
+ asection *sec;
+ struct xcoff_link_hash_entry *hds;
+
+ /* Mark the descriptor (and its TOC section). */
+ hds = h->descriptor;
+ BFD_ASSERT ((hds->root.type == bfd_link_hash_undefined
+ || hds->root.type == bfd_link_hash_undefweak)
+ && (hds->flags & XCOFF_DEF_REGULAR) == 0);
+ if (!xcoff_mark_symbol (info, hds))
+ return FALSE;
+
+ /* Treat this symbol as undefined if the descriptor was. */
+ if ((hds->flags & XCOFF_WAS_UNDEFINED) != 0)
+ h->flags |= XCOFF_WAS_UNDEFINED;
+
+ /* Allocate room for the global linkage code itself. */
+ sec = xcoff_hash_table (info)->linkage_section;
+ h->root.type = bfd_link_hash_defined;
+ h->root.u.def.section = sec;
+ h->root.u.def.value = sec->size;
+ h->smclas = XMC_GL;
+ h->flags |= XCOFF_DEF_REGULAR;
+ sec->size += bfd_xcoff_glink_code_size (info->output_bfd);
+
+ /* The global linkage code requires a TOC entry for the
+ descriptor. */
+ if (hds->toc_section == NULL)
+ {
+ int byte_size;
+
+ /* 32 vs 64
+ xcoff32 uses 4 bytes in the toc.
+ xcoff64 uses 8 bytes in the toc. */
+ if (bfd_xcoff_is_xcoff64 (info->output_bfd))
+ byte_size = 8;
+ else if (bfd_xcoff_is_xcoff32 (info->output_bfd))
+ byte_size = 4;
+ else
+ return FALSE;
+
+ /* Allocate room in the fallback TOC section. */
+ hds->toc_section = xcoff_hash_table (info)->toc_section;
+ hds->u.toc_offset = hds->toc_section->size;
+ hds->toc_section->size += byte_size;
+ if (!xcoff_mark (info, hds->toc_section))
+ return FALSE;
+
+ /* Allocate room for a static and dynamic R_TOC
+ relocation. */
+ ++xcoff_hash_table (info)->ldrel_count;
+ ++hds->toc_section->reloc_count;
+
+ /* Set the index to -2 to force this symbol to
+ get written out. */
+ hds->indx = -2;
+ hds->flags |= XCOFF_SET_TOC | XCOFF_LDREL;
+ }
+ }
+ else if ((h->flags & XCOFF_DEF_DYNAMIC) == 0)
+ {
+ /* Record that the symbol was undefined, then import it.
+ -brtl links use a special fake import file. */
+ h->flags |= XCOFF_WAS_UNDEFINED | XCOFF_IMPORT;
+ if (xcoff_hash_table (info)->rtld)
+ {
+ if (!xcoff_set_import_path (info, h, "", "..", ""))
+ return FALSE;
+ }
+ else
+ {
+ if (!xcoff_set_import_path (info, h, NULL, NULL, NULL))
+ return FALSE;
+ }
+ }
+ }
+
if (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
{
@@ -2320,15 +2536,9 @@ xcoff_mark (struct bfd_link_info *info, asection *sec)
|| h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak
|| h->root.type == bfd_link_hash_common
- || ((h->flags & XCOFF_CALLED) != 0
- && (h->root.type == bfd_link_hash_undefined
- || h->root.type == bfd_link_hash_undefweak)
- && h->root.root.string[0] == '.'
- && h->descriptor != NULL
- && ((h->descriptor->flags & XCOFF_DEF_DYNAMIC) != 0
- || ((h->descriptor->flags & XCOFF_IMPORT) != 0
- && (h->descriptor->flags
- & XCOFF_DEF_REGULAR) == 0))))
+ /* We will always provide a local definition of
+ function symbols. */
+ || (h->flags & XCOFF_CALLED) != 0)
break;
/* Fall through. */
case R_POS:
@@ -2483,8 +2693,7 @@ bfd_xcoff_import_symbol (bfd *output_bfd,
hds->root.u.undef.abfd = h->root.u.undef.abfd;
}
hds->flags |= XCOFF_DESCRIPTOR;
- BFD_ASSERT ((hds->flags & XCOFF_CALLED) == 0
- && (h->flags & XCOFF_DESCRIPTOR) == 0);
+ BFD_ASSERT ((h->flags & XCOFF_DESCRIPTOR) == 0);
hds->descriptor = h;
h->descriptor = hds;
}
@@ -2516,46 +2725,8 @@ bfd_xcoff_import_symbol (bfd *output_bfd,
h->root.u.def.value = val;
}
- /* We overload the ldindx field to hold the l_ifile value for this
- symbol. */
- BFD_ASSERT (h->ldsym == NULL);
- BFD_ASSERT ((h->flags & XCOFF_BUILT_LDSYM) == 0);
- if (imppath == NULL)
- h->ldindx = -1;
- else
- {
- unsigned int c;
- struct xcoff_import_file **pp;
-
- /* We start c at 1 because the first entry in the import list is
- reserved for the library search path. */
- for (pp = &xcoff_hash_table (info)->imports, c = 1;
- *pp != NULL;
- pp = &(*pp)->next, ++c)
- {
- if (strcmp ((*pp)->path, imppath) == 0
- && strcmp ((*pp)->file, impfile) == 0
- && strcmp ((*pp)->member, impmember) == 0)
- break;
- }
-
- if (*pp == NULL)
- {
- struct xcoff_import_file *n;
- bfd_size_type amt = sizeof (* n);
-
- n = bfd_alloc (output_bfd, amt);
- if (n == NULL)
- return FALSE;
- n->next = NULL;
- n->path = imppath;
- n->file = impfile;
- n->member = impmember;
- *pp = n;
- }
-
- h->ldindx = c;
- }
+ if (!xcoff_set_import_path (info, h, imppath, impfile, impmember))
+ return FALSE;
return TRUE;
}
@@ -2577,34 +2748,6 @@ bfd_xcoff_export_symbol (bfd *output_bfd,
/* FIXME: I'm not at all sure what syscall is supposed to mean, so
I'm just going to ignore it until somebody explains it. */
- /* See if this is a function descriptor. It may be one even though
- it is not so marked. */
- if ((h->flags & XCOFF_DESCRIPTOR) == 0
- && h->root.root.string[0] != '.')
- {
- char *fnname;
- struct xcoff_link_hash_entry *hfn;
- bfd_size_type amt = strlen (h->root.root.string) + 2;
-
- fnname = bfd_malloc (amt);
- if (fnname == NULL)
- return FALSE;
- fnname[0] = '.';
- strcpy (fnname + 1, h->root.root.string);
- hfn = xcoff_link_hash_lookup (xcoff_hash_table (info),
- fnname, FALSE, FALSE, TRUE);
- free (fnname);
- if (hfn != NULL
- && hfn->smclas == XMC_PR
- && (hfn->root.type == bfd_link_hash_defined
- || hfn->root.type == bfd_link_hash_defweak))
- {
- h->flags |= XCOFF_DESCRIPTOR;
- h->descriptor = hfn;
- hfn->descriptor = h;
- }
- }
-
/* Make sure we don't garbage collect this symbol. */
if (! xcoff_mark_symbol (info, h))
return FALSE;
@@ -2767,115 +2910,16 @@ xcoff_build_ldsyms (struct xcoff_link_hash_entry *h, void * p)
!= ldinfo->info->output_bfd->xvec)))
h->flags |= XCOFF_MARK;
- /* If this symbol is called and defined in a dynamic object, or it
- is imported, then we need to set up global linkage code for it.
- (Unless we did garbage collection and we didn't need this
- symbol.) */
- if ((h->flags & XCOFF_CALLED) != 0
- && (h->root.type == bfd_link_hash_undefined
- || h->root.type == bfd_link_hash_undefweak)
- && h->root.root.string[0] == '.'
- && h->descriptor != NULL
- && ((h->descriptor->flags & XCOFF_DEF_DYNAMIC) != 0
- || ((h->descriptor->flags & XCOFF_IMPORT) != 0
- && (h->descriptor->flags & XCOFF_DEF_REGULAR) == 0))
- && (! xcoff_hash_table (ldinfo->info)->gc
- || (h->flags & XCOFF_MARK) != 0))
- {
- asection *sec;
- struct xcoff_link_hash_entry *hds;
-
- sec = xcoff_hash_table (ldinfo->info)->linkage_section;
- h->root.type = bfd_link_hash_defined;
- h->root.u.def.section = sec;
- h->root.u.def.value = sec->size;
- h->smclas = XMC_GL;
- h->flags |= XCOFF_DEF_REGULAR;
- sec->size += bfd_xcoff_glink_code_size(ldinfo->output_bfd);
-
- /* The global linkage code requires a TOC entry for the
- descriptor. */
- hds = h->descriptor;
- BFD_ASSERT ((hds->root.type == bfd_link_hash_undefined
- || hds->root.type == bfd_link_hash_undefweak)
- && (hds->flags & XCOFF_DEF_REGULAR) == 0);
- hds->flags |= XCOFF_MARK;
- if (hds->toc_section == NULL)
- {
- int byte_size;
-
- /* 32 vs 64
- xcoff32 uses 4 bytes in the toc.
- xcoff64 uses 8 bytes in the toc. */
- if (bfd_xcoff_is_xcoff64 (ldinfo->output_bfd))
- byte_size = 8;
- else if (bfd_xcoff_is_xcoff32 (ldinfo->output_bfd))
- byte_size = 4;
- else
- return FALSE;
-
- hds->toc_section = xcoff_hash_table (ldinfo->info)->toc_section;
- hds->u.toc_offset = hds->toc_section->size;
- hds->toc_section->size += byte_size;
- ++xcoff_hash_table (ldinfo->info)->ldrel_count;
- ++hds->toc_section->reloc_count;
- hds->indx = -2;
- hds->flags |= XCOFF_SET_TOC | XCOFF_LDREL;
-
- /* We need to call xcoff_build_ldsyms recursively here,
- because we may already have passed hds on the traversal. */
- xcoff_build_ldsyms (hds, p);
- }
- }
-
/* If this symbol is exported, but not defined, we need to try to
define it. */
if ((h->flags & XCOFF_EXPORT) != 0
- && (h->flags & XCOFF_IMPORT) == 0
- && (h->flags & XCOFF_DEF_REGULAR) == 0
- && (h->flags & XCOFF_DEF_DYNAMIC) == 0
- && (h->root.type == bfd_link_hash_undefined
- || h->root.type == bfd_link_hash_undefweak))
+ && (h->flags & XCOFF_WAS_UNDEFINED) != 0)
{
- if ((h->flags & XCOFF_DESCRIPTOR) != 0
- && (h->descriptor->root.type == bfd_link_hash_defined
- || h->descriptor->root.type == bfd_link_hash_defweak))
- {
- asection *sec;
-
- /* This is an undefined function descriptor associated with
- a defined entry point. We can build up a function
- descriptor ourselves. Believe it or not, the AIX linker
- actually does this, and there are cases where we need to
- do it as well. */
- sec = xcoff_hash_table (ldinfo->info)->descriptor_section;
- h->root.type = bfd_link_hash_defined;
- h->root.u.def.section = sec;
- h->root.u.def.value = sec->size;
- h->smclas = XMC_DS;
- h->flags |= XCOFF_DEF_REGULAR;
-
- /* The size of the function descriptor depends if this is an
- xcoff32 (12) or xcoff64 (24). */
- sec->size +=
- bfd_xcoff_function_descriptor_size(ldinfo->output_bfd);
-
- /* A function descriptor uses two relocs: one for the
- associated code, and one for the TOC address. */
- xcoff_hash_table (ldinfo->info)->ldrel_count += 2;
- sec->reloc_count += 2;
-
- /* We handle writing out the contents of the descriptor in
- xcoff_write_global_symbol. */
- }
- else
- {
- (*_bfd_error_handler)
- (_("warning: attempt to export undefined symbol `%s'"),
- h->root.root.string);
- h->ldsym = NULL;
- return TRUE;
- }
+ (*_bfd_error_handler)
+ (_("warning: attempt to export undefined symbol `%s'"),
+ h->root.root.string);
+ h->ldsym = NULL;
+ return TRUE;
}
/* If this is still a common symbol, and it wasn't garbage
@@ -3017,6 +3061,7 @@ bfd_xcoff_size_dynamic_sections (bfd *output_bfd,
xcoff_hash_table (info)->file_align = file_align;
xcoff_hash_table (info)->textro = textro;
+ xcoff_hash_table (info)->rtld = rtld;
hentry = NULL;
if (entry != NULL)
@@ -4318,7 +4363,6 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo,
{
struct xcoff_link_hash_entry *h = NULL;
struct internal_ldrel ldrel;
- bfd_boolean quiet;
*rel_hash = NULL;
@@ -4451,7 +4495,6 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo,
}
}
- quiet = FALSE;
switch (irel->r_type)
{
default:
@@ -4507,17 +4550,7 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo,
}
else
{
- if (! finfo->info->relocatable
- && (h->flags & XCOFF_DEF_DYNAMIC) == 0
- && (h->flags & XCOFF_IMPORT) == 0)
- {
- /* We already called the undefined_symbol
- callback for this relocation, in
- _bfd_ppc_xcoff_relocate_section. Don't
- issue any more warnings. */
- quiet = TRUE;
- }
- if (h->ldindx < 0 && ! quiet)
+ if (h->ldindx < 0)
{
(*_bfd_error_handler)
(_("%B: `%s' in loader reloc but not loader sym"),
@@ -4531,8 +4564,7 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo,
ldrel.l_rtype = (irel->r_size << 8) | irel->r_type;
ldrel.l_rsecnm = o->output_section->target_index;
if (xcoff_hash_table (finfo->info)->textro
- && strcmp (o->output_section->name, ".text") == 0
- && ! quiet)
+ && strcmp (o->output_section->name, ".text") == 0)
{
(*_bfd_error_handler)
(_("%B: loader reloc in read-only section %A"),