/* POWER/PowerPC XCOFF linker support.
Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
- 2005, 2006, 2007 Free Software Foundation, Inc.
+ 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
Written by Ian Lance Taylor <ian@cygnus.com>, Cygnus Support.
This file is part of BFD, the Binary File Descriptor library.
symbuf->symbol.flags = BSF_NO_FLAGS;
if ((ldsym.l_smtype & L_EXPORT) != 0)
- symbuf->symbol.flags |= BSF_GLOBAL;
+ {
+ if ((ldsym.l_smtype & L_WEAK) != 0)
+ symbuf->symbol.flags |= BSF_WEAK;
+ else
+ symbuf->symbol.flags |= BSF_GLOBAL;
+ }
/* FIXME: We have no way to record the other information stored
with the loader symbol. */
require_internal, internal_relocs);
}
\f
+/* H is the bfd symbol associated with exported .loader symbol LDSYM.
+ Return true if LDSYM defines H. */
+
+static bfd_boolean
+xcoff_dynamic_definition_p (struct xcoff_link_hash_entry *h,
+ struct internal_ldsym *ldsym)
+{
+ /* If we didn't know about H before processing LDSYM, LDSYM
+ definitely defines H. */
+ if (h->root.type == bfd_link_hash_new)
+ return TRUE;
+
+ /* If H is currently a weak dynamic symbol, and if LDSYM is a strong
+ dynamic symbol, LDSYM trumps the current definition of H. */
+ if ((ldsym->l_smtype & L_WEAK) == 0
+ && (h->flags & XCOFF_DEF_DYNAMIC) != 0
+ && (h->flags & XCOFF_DEF_REGULAR) == 0
+ && (h->root.type == bfd_link_hash_defweak
+ || h->root.type == bfd_link_hash_undefweak))
+ return TRUE;
+
+ /* If H is currently undefined, LDSYM defines it. */
+ if ((h->flags & XCOFF_DEF_DYNAMIC) == 0
+ && (h->root.type == bfd_link_hash_undefined
+ || h->root.type == bfd_link_hash_undefweak))
+ return TRUE;
+
+ return FALSE;
+}
+
/* This function is used to add symbols from a dynamic object to the
global symbol table. */
/* We can only handle a dynamic object if we are generating an XCOFF
output file. */
- if (info->hash->creator != abfd->xvec)
+ if (info->output_bfd->xvec != abfd->xvec)
{
(*_bfd_error_handler)
(_("%s: XCOFF shared object when not producing XCOFF output"),
if (h == NULL)
return FALSE;
- h->flags |= XCOFF_DEF_DYNAMIC;
-
- /* If the symbol is undefined, and the BFD it was found in is
- not a dynamic object, change the BFD to this dynamic object,
- so that we can get the correct import file ID. */
- if ((h->root.type == bfd_link_hash_undefined
- || h->root.type == bfd_link_hash_undefweak)
- && (h->root.u.undef.abfd == NULL
- || (h->root.u.undef.abfd->flags & DYNAMIC) == 0))
- h->root.u.undef.abfd = abfd;
-
- if (h->root.type == bfd_link_hash_new)
- {
- h->root.type = bfd_link_hash_undefined;
- h->root.u.undef.abfd = abfd;
- /* We do not want to add this to the undefined symbol list. */
- }
-
- if (h->smclas == XMC_UA
- || h->root.type == bfd_link_hash_undefined
- || h->root.type == bfd_link_hash_undefweak)
- h->smclas = ldsym.l_smclas;
-
- /* Unless this is an XMC_XO symbol, we don't bother to actually
- define it, since we don't have a section to put it in anyhow.
- Instead, the relocation routines handle the DEF_DYNAMIC flag
- correctly. */
+ if (!xcoff_dynamic_definition_p (h, &ldsym))
+ continue;
- if (h->smclas == XMC_XO
- && (h->root.type == bfd_link_hash_undefined
- || h->root.type == bfd_link_hash_undefweak))
+ h->flags |= XCOFF_DEF_DYNAMIC;
+ h->smclas = ldsym.l_smclas;
+ if (h->smclas == XMC_XO)
{
/* This symbol has an absolute value. */
- h->root.type = bfd_link_hash_defined;
+ if ((ldsym.l_smtype & L_WEAK) != 0)
+ h->root.type = bfd_link_hash_defweak;
+ else
+ h->root.type = bfd_link_hash_defined;
h->root.u.def.section = bfd_abs_section_ptr;
h->root.u.def.value = ldsym.l_value;
}
+ else
+ {
+ /* Otherwise, we don't bother to actually define the symbol,
+ since we don't have a section to put it in anyhow.
+ We assume instead that an undefined XCOFF_DEF_DYNAMIC symbol
+ should be imported from the symbol's undef.abfd. */
+ if ((ldsym.l_smtype & L_WEAK) != 0)
+ h->root.type = bfd_link_hash_undefweak;
+ else
+ h->root.type = bfd_link_hash_undefined;
+ h->root.u.undef.abfd = abfd;
+ }
/* If this symbol defines a function descriptor, then it
implicitly defines the function code as well. */
if (hds == NULL)
return FALSE;
- if (hds->root.type == bfd_link_hash_new)
- {
- hds->root.type = bfd_link_hash_undefined;
- hds->root.u.undef.abfd = abfd;
- /* We do not want to add this to the undefined
- symbol list. */
- }
-
hds->descriptor = h;
h->descriptor = hds;
}
- hds->flags |= XCOFF_DEF_DYNAMIC;
- if (hds->smclas == XMC_UA)
- hds->smclas = XMC_PR;
-
- /* An absolute symbol appears to actually define code, not a
- function descriptor. This is how some math functions are
- implemented on AIX 4.1. */
- if (h->smclas == XMC_XO
- && (hds->root.type == bfd_link_hash_undefined
- || hds->root.type == bfd_link_hash_undefweak))
+ if (xcoff_dynamic_definition_p (hds, &ldsym))
{
- hds->smclas = XMC_XO;
- hds->root.type = bfd_link_hash_defined;
- hds->root.u.def.section = bfd_abs_section_ptr;
- hds->root.u.def.value = ldsym.l_value;
+ hds->root.type = h->root.type;
+ hds->flags |= XCOFF_DEF_DYNAMIC;
+ if (h->smclas == XMC_XO)
+ {
+ /* An absolute symbol appears to actually define code, not a
+ function descriptor. This is how some math functions are
+ implemented on AIX 4.1. */
+ hds->smclas = XMC_XO;
+ hds->root.u.def.section = bfd_abs_section_ptr;
+ hds->root.u.def.value = ldsym.l_value;
+ }
+ else
+ {
+ hds->smclas = XMC_PR;
+ hds->root.u.undef.abfd = abfd;
+ /* We do not want to add this to the undefined
+ symbol list. */
+ }
}
}
}
{
bfd_boolean return_value = FALSE;
- if (info->hash->creator == abfd->xvec)
+ if (info->output_bfd->xvec == abfd->xvec)
{
/* We need to build a .loader section, so we do it here. This
won't work if we're producing an XCOFF output file with no
bfd_size_type symcount;
struct xcoff_link_hash_entry **sym_hash;
asection **csect_cache;
+ unsigned int *lineno_counts;
bfd_size_type linesz;
asection *o;
asection *last_real;
goto error_return;
xcoff_data (abfd)->csects = csect_cache;
+ /* We garbage-collect line-number information on a symbol-by-symbol
+ basis, so we need to have quick access to the number of entries
+ per symbol. */
+ amt = symcount * sizeof (unsigned int);
+ lineno_counts = bfd_zalloc (abfd, amt);
+ if (lineno_counts == NULL && symcount != 0)
+ goto error_return;
+ xcoff_data (abfd)->lineno_counts = lineno_counts;
+
/* While splitting sections into csects, we need to assign the
relocs correctly. The relocs and the csects must both be in
order by VMA within a given section, so we handle this by
const char *name;
char buf[SYMNMLEN + 1];
int smtyp;
- flagword flags;
asection *section;
bfd_vma value;
struct xcoff_link_hash_entry *set_toc;
/* In this pass we are only interested in symbols with csect
information. */
- if (sym.n_sclass != C_EXT && sym.n_sclass != C_HIDEXT)
+ if (!CSECT_SYM_P (sym.n_sclass))
{
/* Set csect_cache,
Normally csect is a .pr, .rw etc. created in the loop
If C_FILE or first time, handle special
- Advance esym, sym_hash, csect_hash ptr's
- Keep track of the last_symndx for the current file. */
- if (sym.n_sclass == C_FILE && csect != NULL)
- {
- xcoff_section_data (abfd, csect)->last_symndx =
- ((esym
- - (bfd_byte *) obj_coff_external_syms (abfd))
- / symesz);
- csect = NULL;
- }
-
+ Advance esym, sym_hash, csect_hash ptrs. */
+ if (sym.n_sclass == C_FILE)
+ csect = NULL;
if (csect != NULL)
*csect_cache = csect;
else if (first_csect == NULL || sym.n_sclass == C_FILE)
esym += (sym.n_numaux + 1) * symesz;
sym_hash += sym.n_numaux + 1;
csect_cache += sym.n_numaux + 1;
+ lineno_counts += sym.n_numaux + 1;
continue;
}
if (lin.l_lnno == 0)
break;
}
- csect->lineno_count += (linp - linpstart) / linesz;
+ *lineno_counts = (linp - linpstart) / linesz;
/* The setting of line_filepos will only be
useful if all the line number entries for a
csect are contiguous; this only matters for
smtyp = SMTYP_SMTYP (aux.x_csect.x_smtyp);
- flags = BSF_GLOBAL;
section = NULL;
value = 0;
set_toc = NULL;
break;
case XTY_SD:
- /* This is a csect definition. */
- if (csect != NULL)
- {
- xcoff_section_data (abfd, csect)->last_symndx =
- ((esym - (bfd_byte *) obj_coff_external_syms (abfd)) / symesz);
- }
-
csect = NULL;
csect_index = -(unsigned) 1;
place. */
if (aux.x_csect.x_smclas == XMC_TC
&& sym.n_sclass == C_HIDEXT
- && info->hash->creator == abfd->xvec
+ && info->output_bfd->xvec == abfd->xvec
&& ((bfd_xcoff_is_xcoff32 (abfd)
&& aux.x_csect.x_scnlen.l == 4)
|| (bfd_xcoff_is_xcoff64 (abfd)
erelsym = ((bfd_byte *) obj_coff_external_syms (abfd)
+ rel->r_symndx * symesz);
bfd_coff_swap_sym_in (abfd, (void *) erelsym, (void *) &relsym);
- if (relsym.n_sclass == C_EXT)
+ if (EXTERN_SYM_P (relsym.n_sclass))
{
const char *relname;
char relbuf[SYMNMLEN + 1];
if (first_csect == NULL)
first_csect = csect;
- /* If this symbol is C_EXT, we treat it as starting at the
+ /* If this symbol is external, we treat it as starting at the
beginning of the newly created section. */
- if (sym.n_sclass == C_EXT)
+ if (EXTERN_SYM_P (sym.n_sclass))
{
section = csect;
value = 0;
named .tocbss, and rely on the linker script to put that
in the TOC area. */
- if (csect != NULL)
- {
- xcoff_section_data (abfd, csect)->last_symndx =
- ((esym
- - (bfd_byte *) obj_coff_external_syms (abfd))
- / symesz);
- }
-
if (aux.x_csect.x_smclas == XMC_TD)
{
/* The linker script puts the .td section in the data
if (first_csect == NULL)
first_csect = csect;
- if (sym.n_sclass == C_EXT)
+ if (EXTERN_SYM_P (sym.n_sclass))
{
csect->flags |= SEC_IS_COMMON;
csect->size = 0;
/* Now we have enough information to add the symbol to the
linker hash table. */
- if (sym.n_sclass == C_EXT)
+ if (EXTERN_SYM_P (sym.n_sclass))
{
bfd_boolean copy;
+ flagword flags;
BFD_ASSERT (section != NULL);
shared object, which will cause symbol redefinitions,
although this is an easier case to detect. */
- if (info->hash->creator == abfd->xvec)
+ if (info->output_bfd->xvec == abfd->xvec)
{
if (! bfd_is_und_section (section))
*sym_hash = xcoff_link_hash_lookup (xcoff_hash_table (info),
section = bfd_und_section_ptr;
value = 0;
}
- else if (((*sym_hash)->root.u.def.section->owner->flags
- & DYNAMIC) != 0)
+ else if (((*sym_hash)->flags & XCOFF_DEF_REGULAR) == 0
+ && ((*sym_hash)->flags & XCOFF_DEF_DYNAMIC) != 0)
{
/* The existing symbol is from a shared library.
Replace it. */
section = bfd_und_section_ptr;
value = 0;
}
+ else if (sym.n_sclass == C_AIX_WEAKEXT
+ || (*sym_hash)->root.type == bfd_link_hash_defweak)
+ {
+ /* At least one of the definitions is weak.
+ Allow the normal rules to take effect. */
+ }
else if ((*sym_hash)->root.u.undef.next != NULL
|| info->hash->undefs_tail == &(*sym_hash)->root)
{
}
}
else if (((*sym_hash)->flags & XCOFF_MULTIPLY_DEFINED) != 0
- && ((*sym_hash)->root.type == bfd_link_hash_defined
- || (*sym_hash)->root.type == bfd_link_hash_defweak)
+ && (*sym_hash)->root.type == bfd_link_hash_defined
&& (bfd_is_und_section (section)
|| bfd_is_com_section (section)))
{
a second time from the csects. */
BFD_ASSERT (last_real->next == first_csect);
last_real->next = NULL;
+ flags = (sym.n_sclass == C_EXT ? BSF_GLOBAL : BSF_WEAK);
if (! (_bfd_generic_link_add_one_symbol
(info, abfd, name, flags, section, value,
NULL, copy, TRUE,
= csect->alignment_power;
}
- if (info->hash->creator == abfd->xvec)
+ if (info->output_bfd->xvec == abfd->xvec)
{
int flag;
}
}
- *csect_cache = csect;
+ if (smtyp == XTY_ER)
+ *csect_cache = section;
+ else
+ {
+ *csect_cache = csect;
+ if (csect != NULL)
+ xcoff_section_data (abfd, csect)->last_symndx
+ = (esym - (bfd_byte *) obj_coff_external_syms (abfd)) / symesz;
+ }
esym += (sym.n_numaux + 1) * symesz;
sym_hash += sym.n_numaux + 1;
csect_cache += sym.n_numaux + 1;
+ lineno_counts += sym.n_numaux + 1;
}
BFD_ASSERT (last_real == NULL || last_real->next == first_csect);
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. */
- if (info->hash->creator == abfd->xvec
+ /* 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
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;
}
}
if ((abfd->flags & DYNAMIC) != 0
&& ! info->static_link
- && info->hash->creator == abfd->xvec)
+ && info->output_bfd->xvec == abfd->xvec)
return xcoff_link_check_dynamic_ar_symbols (abfd, info, pneeded);
symesz = bfd_coff_symesz (abfd);
bfd_coff_swap_sym_in (abfd, (void *) esym, (void *) &sym);
- if (sym.n_sclass == C_EXT && sym.n_scnum != N_UNDEF)
+ if (EXTERN_SYM_P (sym.n_sclass) && sym.n_scnum != N_UNDEF)
{
const char *name;
char buf[SYMNMLEN + 1];
undefined references in shared objects. */
if (h != NULL
&& h->type == bfd_link_hash_undefined
- && (info->hash->creator != abfd->xvec
+ && (info->output_bfd->xvec != abfd->xvec
|| (((struct xcoff_link_hash_entry *) h)->flags
& XCOFF_DEF_DYNAMIC) == 0))
{
struct bfd_link_info *info,
bfd_boolean *pneeded)
{
+ bfd_boolean keep_syms_p;
+
+ keep_syms_p = (obj_coff_external_syms (abfd) != NULL);
if (! _bfd_coff_get_external_symbols (abfd))
return FALSE;
{
if (! xcoff_link_add_symbols (abfd, info))
return FALSE;
+ if (info->keep_memory)
+ keep_syms_p = TRUE;
}
- if (! info->keep_memory || ! *pneeded)
+ if (!keep_syms_p)
{
if (! _bfd_coff_free_symbols (abfd))
return FALSE;
while (member != NULL)
{
if (bfd_check_format (member, bfd_object)
- && (info->hash->creator == member->xvec)
+ && (info->output_bfd->xvec == member->xvec)
&& (! bfd_has_map (abfd) || (member->flags & DYNAMIC) != 0))
{
bfd_boolean needed;
}
}
\f
+/* 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;
+}
+\f
+/* Return true if the given bfd contains at least one shared object. */
+
+static bfd_boolean
+xcoff_archive_contains_shared_object_p (bfd *archive)
+{
+ bfd *member;
+
+ member = bfd_openr_next_archived_file (archive, NULL);
+ while (member != NULL && (member->flags & DYNAMIC) == 0)
+ member = bfd_openr_next_archived_file (archive, member);
+ return member != NULL;
+}
+
+/* Symbol H qualifies for export by -bexpfull. Return true if it also
+ qualifies for export by -bexpall. */
+
+static bfd_boolean
+xcoff_covered_by_expall_p (struct xcoff_link_hash_entry *h)
+{
+ /* Exclude symbols beginning with '_'. */
+ if (h->root.root.string[0] == '_')
+ return FALSE;
+
+ /* Exclude archive members that would otherwise be unreferenced. */
+ if ((h->flags & XCOFF_MARK) == 0
+ && (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ && h->root.u.def.section->owner != NULL
+ && h->root.u.def.section->owner->my_archive != NULL)
+ return FALSE;
+
+ return TRUE;
+}
+
+/* Return true if symbol H qualifies for the forms of automatic export
+ specified by AUTO_EXPORT_FLAGS. */
+
+static bfd_boolean
+xcoff_auto_export_p (struct xcoff_link_hash_entry *h,
+ unsigned int auto_export_flags)
+{
+ /* Don't automatically export things that were explicitly exported. */
+ if ((h->flags & XCOFF_EXPORT) != 0)
+ return FALSE;
+
+ /* Don't export things that we don't define. */
+ if ((h->flags & XCOFF_DEF_REGULAR) == 0)
+ return FALSE;
+
+ /* Don't export functions; export their descriptors instead. */
+ if (h->root.root.string[0] == '.')
+ return FALSE;
+
+ /* We don't export a symbol which is being defined by an object
+ included from an archive which contains a shared object. The
+ rationale is that if an archive contains both an unshared and
+ a shared object, then there must be some reason that the
+ unshared object is unshared, and we don't want to start
+ providing a shared version of it. In particular, this solves
+ a bug involving the _savefNN set of functions. gcc will call
+ those functions without providing a slot to restore the TOC,
+ so it is essential that these functions be linked in directly
+ and not from a shared object, which means that a shared
+ object which also happens to link them in must not export
+ them. This is confusing, but I haven't been able to think of
+ a different approach. Note that the symbols can, of course,
+ be exported explicitly. */
+ if (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ {
+ bfd *owner;
+
+ owner = h->root.u.def.section->owner;
+ if (owner != NULL
+ && owner->my_archive != NULL
+ && xcoff_archive_contains_shared_object_p (owner->my_archive))
+ return FALSE;
+ }
+
+ /* Otherwise, all symbols are exported by -bexpfull. */
+ if ((auto_export_flags & XCOFF_EXPFULL) != 0)
+ return TRUE;
+
+ /* Despite its name, -bexpall exports most but not all symbols. */
+ if ((auto_export_flags & XCOFF_EXPALL) != 0
+ && xcoff_covered_by_expall_p (h))
+ return TRUE;
+
+ return FALSE;
+}
+\f
/* Mark a symbol as not being garbage, including the section in which
it is defined. */
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;
+
+ /* Mark the TOC section, so that we get an anchor
+ to relocate against. */
+ if (!xcoff_mark (info, xcoff_hash_table (info)->toc_section))
+ 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)
{
return TRUE;
}
+/* Look for a symbol called NAME. If the symbol is defined, mark it.
+ If the symbol exists, set FLAGS. */
+
+static bfd_boolean
+xcoff_mark_symbol_by_name (struct bfd_link_info *info,
+ const char *name, unsigned int flags)
+{
+ struct xcoff_link_hash_entry *h;
+
+ h = xcoff_link_hash_lookup (xcoff_hash_table (info), name,
+ FALSE, FALSE, TRUE);
+ if (h != NULL)
+ {
+ h->flags |= flags;
+ if (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ {
+ if (!xcoff_mark (info, h->root.u.def.section))
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
/* The mark phase of garbage collection. For a given section, mark
it, and all the sections which define symbols to which it refers.
Because this function needs to look at the relocs, we also count
sec->flags |= SEC_MARK;
- if (sec->owner->xvec == info->hash->creator
+ if (sec->owner->xvec == info->output_bfd->xvec
&& coff_section_data (sec->owner, sec) != NULL
&& xcoff_section_data (sec->owner, sec) != NULL)
{
- struct xcoff_link_hash_entry **hp, **hpend;
+ struct xcoff_link_hash_entry **syms;
struct internal_reloc *rel, *relend;
+ asection **csects;
+ unsigned long i, first, last;
/* Mark all the symbols in this section. */
- hp = (obj_xcoff_sym_hashes (sec->owner)
- + xcoff_section_data (sec->owner, sec)->first_symndx);
- hpend = (obj_xcoff_sym_hashes (sec->owner)
- + xcoff_section_data (sec->owner, sec)->last_symndx);
- for (; hp < hpend; hp++)
- {
- struct xcoff_link_hash_entry *h;
-
- h = *hp;
- if (h != NULL
- && (h->flags & XCOFF_MARK) == 0)
- {
- if (! xcoff_mark_symbol (info, h))
- return FALSE;
- }
- }
+ syms = obj_xcoff_sym_hashes (sec->owner);
+ csects = xcoff_data (sec->owner)->csects;
+ first = xcoff_section_data (sec->owner, sec)->first_symndx;
+ last = xcoff_section_data (sec->owner, sec)->last_symndx;
+ for (i = first; i <= last; i++)
+ if (csects[i] == sec
+ && syms[i] != NULL
+ && (syms[i]->flags & XCOFF_MARK) == 0)
+ {
+ if (!xcoff_mark_symbol (info, syms[i]))
+ return FALSE;
+ }
/* Look through the section relocs. */
if ((sec->flags & SEC_RELOC) != 0
relend = rel + sec->reloc_count;
for (; rel < relend; rel++)
{
- asection *rsec;
struct xcoff_link_hash_entry *h;
if ((unsigned int) rel->r_symndx
continue;
h = obj_xcoff_sym_hashes (sec->owner)[rel->r_symndx];
- if (h != NULL
- && (h->flags & XCOFF_MARK) == 0)
+ if (h != NULL)
{
- if (! xcoff_mark_symbol (info, h))
- return FALSE;
+ if ((h->flags & XCOFF_MARK) == 0)
+ {
+ if (!xcoff_mark_symbol (info, h))
+ return FALSE;
+ }
}
-
- rsec = xcoff_data (sec->owner)->csects[rel->r_symndx];
- if (rsec != NULL
- && (rsec->flags & SEC_MARK) == 0)
+ else
{
- if (! xcoff_mark (info, rsec))
- return FALSE;
+ asection *rsec;
+
+ rsec = xcoff_data (sec->owner)->csects[rel->r_symndx];
+ if (rsec != NULL
+ && (rsec->flags & SEC_MARK) == 0)
+ {
+ if (!xcoff_mark (info, rsec))
+ return FALSE;
+ }
}
/* See if this reloc needs to be copied into the .loader
|| 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:
case R_NEG:
case R_RL:
case R_RLA:
+ if (h != NULL
+ && (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ && bfd_is_abs_section (h->root.u.def.section))
+ break;
++xcoff_hash_table (info)->ldrel_count;
if (h != NULL)
h->flags |= XCOFF_LDREL;
/* Keep all sections from non-XCOFF input files. Keep
special sections. Keep .debug sections for the
moment. */
- if (sub->xvec != info->hash->creator
+ if (sub->xvec != info->output_bfd->xvec
|| o == xcoff_hash_table (info)->debug_section
|| o == xcoff_hash_table (info)->loader_section
|| o == xcoff_hash_table (info)->linkage_section
- || o == xcoff_hash_table (info)->toc_section
|| o == xcoff_hash_table (info)->descriptor_section
|| strcmp (o->name, ".debug") == 0)
o->flags |= SEC_MARK;
{
o->size = 0;
o->reloc_count = 0;
- o->lineno_count = 0;
}
}
}
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;
}
h->root.type = bfd_link_hash_defined;
h->root.u.def.section = bfd_abs_section_ptr;
h->root.u.def.value = val;
+ h->smclas = XMC_XO;
}
- /* 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;
}
/* 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;
return TRUE;
}
+/* An xcoff_link_hash_traverse callback for which DATA points to an
+ xcoff_loader_info. Mark all symbols that should be automatically
+ exported. */
+
+static bfd_boolean
+xcoff_mark_auto_exports (struct xcoff_link_hash_entry *h, void *data)
+{
+ struct xcoff_loader_info *ldinfo;
+
+ ldinfo = (struct xcoff_loader_info *) data;
+ if (xcoff_auto_export_p (h, ldinfo->auto_export_flags))
+ {
+ if (!xcoff_mark_symbol (ldinfo->info, h))
+ ldinfo->failed = TRUE;
+ }
+ return TRUE;
+}
+
/* Add a symbol to the .loader symbols, if necessary. */
+/* INPUT_BFD has an external symbol associated with hash table entry H
+ and csect CSECT. Return true if INPUT_BFD defines H. */
+
+static bfd_boolean
+xcoff_final_definition_p (bfd *input_bfd, struct xcoff_link_hash_entry *h,
+ asection *csect)
+{
+ switch (h->root.type)
+ {
+ case bfd_link_hash_defined:
+ case bfd_link_hash_defweak:
+ /* No input bfd owns absolute symbols. They are written by
+ xcoff_write_global_symbol instead. */
+ return (!bfd_is_abs_section (csect)
+ && h->root.u.def.section == csect);
+
+ case bfd_link_hash_common:
+ return h->root.u.c.p->section->owner == input_bfd;
+
+ case bfd_link_hash_undefined:
+ case bfd_link_hash_undefweak:
+ /* We can't treat undef.abfd as the owner because that bfd
+ might be a dynamic object. Allow any bfd to claim it. */
+ return TRUE;
+
+ default:
+ abort ();
+ }
+}
+
static bfd_boolean
xcoff_build_ldsyms (struct xcoff_link_hash_entry *h, void * p)
{
/* If all defined symbols should be exported, mark them now. We
don't want to export the actual functions, just the function
descriptors. */
- if (ldinfo->export_defineds
- && (h->flags & XCOFF_DEF_REGULAR) != 0
- && h->root.root.string[0] != '.')
- {
- bfd_boolean export;
-
- /* We don't export a symbol which is being defined by an object
- included from an archive which contains a shared object. The
- rationale is that if an archive contains both an unshared and
- a shared object, then there must be some reason that the
- unshared object is unshared, and we don't want to start
- providing a shared version of it. In particular, this solves
- a bug involving the _savefNN set of functions. gcc will call
- those functions without providing a slot to restore the TOC,
- so it is essential that these functions be linked in directly
- and not from a shared object, which means that a shared
- object which also happens to link them in must not export
- them. This is confusing, but I haven't been able to think of
- a different approach. Note that the symbols can, of course,
- be exported explicitly. */
- export = TRUE;
- if ((h->root.type == bfd_link_hash_defined
- || h->root.type == bfd_link_hash_defweak)
- && h->root.u.def.section->owner != NULL
- && h->root.u.def.section->owner->my_archive != NULL)
- {
- bfd *arbfd, *member;
-
- arbfd = h->root.u.def.section->owner->my_archive;
- member = bfd_openr_next_archived_file (arbfd, NULL);
- while (member != NULL)
- {
- if ((member->flags & DYNAMIC) != 0)
- {
- export = FALSE;
- break;
- }
- member = bfd_openr_next_archived_file (arbfd, member);
- }
- }
-
- if (export)
- h->flags |= XCOFF_EXPORT;
- }
+ if (xcoff_auto_export_p (h, ldinfo->auto_export_flags))
+ h->flags |= XCOFF_EXPORT;
/* We don't want to garbage collect symbols which are not defined in
XCOFF files. This is a convenient place to mark them. */
|| h->root.type == bfd_link_hash_defweak)
&& (h->root.u.def.section->owner == NULL
|| (h->root.u.def.section->owner->xvec
- != ldinfo->info->hash->creator)))
+ != 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
}
if ((h->flags & XCOFF_IMPORT) != 0)
- h->ldsym->l_ifile = h->ldindx;
+ {
+ /* Give imported descriptors class XMC_DS rather than XMC_UA. */
+ if ((h->flags & XCOFF_DESCRIPTOR) != 0)
+ h->smclas = XMC_DS;
+ h->ldsym->l_ifile = h->ldindx;
+ }
/* The first 3 symbol table indices are reserved to indicate the
data, text and bss sections. */
return TRUE;
}
+
+/* INPUT_BFD includes XCOFF symbol ISYM, which is associated with linker
+ hash table entry H and csect CSECT. AUX contains ISYM's auxillary
+ csect information, if any. NAME is the function's name if the name
+ is stored in the .debug section, otherwise it is null.
+
+ Return 1 if we should include an appropriately-adjusted ISYM
+ in the output file, 0 if we should discard ISYM, or -1 if an
+ error occured. */
+
+static int
+xcoff_keep_symbol_p (struct bfd_link_info *info, bfd *input_bfd,
+ struct internal_syment *isym,
+ union internal_auxent *aux,
+ struct xcoff_link_hash_entry *h,
+ asection *csect, const char *name)
+{
+ int smtyp;
+
+ /* If we are skipping this csect, we want to strip the symbol too. */
+ if (csect == NULL)
+ return 0;
+
+ /* Likewise if we garbage-collected the csect. */
+ if (xcoff_hash_table (info)->gc
+ && !bfd_is_abs_section (csect)
+ && !bfd_is_und_section (csect)
+ && (csect->flags & SEC_MARK) == 0)
+ return 0;
+
+ /* An XCOFF linker always removes C_STAT symbols. */
+ if (isym->n_sclass == C_STAT)
+ return 0;
+
+ /* We generate the TOC anchor separately. */
+ if (isym->n_sclass == C_HIDEXT
+ && aux->x_csect.x_smclas == XMC_TC0)
+ return 0;
+
+ /* If we are stripping all symbols, we want to discard this one. */
+ if (info->strip == strip_all)
+ return 0;
+
+ /* Discard symbols that are defined elsewhere. */
+ if (EXTERN_SYM_P (isym->n_sclass))
+ {
+ if ((h->flags & XCOFF_ALLOCATED) != 0)
+ return 0;
+ if (!xcoff_final_definition_p (input_bfd, h, csect))
+ return 0;
+ }
+
+ /* If we're discarding local symbols, check whether ISYM is local. */
+ smtyp = SMTYP_SMTYP (aux->x_csect.x_smtyp);
+ if (info->discard == discard_all
+ && !EXTERN_SYM_P (isym->n_sclass)
+ && (isym->n_sclass != C_HIDEXT || smtyp != XTY_SD))
+ return 0;
+
+ /* If we're stripping debugging symbols, check whether ISYM is one. */
+ if (info->strip == strip_debugger
+ && isym->n_scnum == N_DEBUG)
+ return 0;
+
+ /* If we are stripping symbols based on name, check how ISYM's
+ name should be handled. */
+ if (info->strip == strip_some
+ || info->discard == discard_l)
+ {
+ char buf[SYMNMLEN + 1];
+
+ if (name == NULL)
+ {
+ name = _bfd_coff_internal_syment_name (input_bfd, isym, buf);
+ if (name == NULL)
+ return -1;
+ }
+
+ if (info->strip == strip_some
+ && bfd_hash_lookup (info->keep_hash, name, FALSE, FALSE) == NULL)
+ return 0;
+
+ if (info->discard == discard_l
+ && !EXTERN_SYM_P (isym->n_sclass)
+ && (isym->n_sclass != C_HIDEXT || smtyp != XTY_SD)
+ && bfd_is_local_label_name (input_bfd, name))
+ return 0;
+ }
+
+ return 1;
+}
+
/* Build the .loader section. This is called by the XCOFF linker
emulation before_allocation routine. We must set the size of the
.loader section before the linker lays out the output file.
-bmaxdata linker option). GC is whether to do garbage collection
(the -bgc linker option). MODTYPE is the module type (the
-bmodtype linker option). TEXTRO is whether the text section must
- be read only (the -btextro linker option). EXPORT_DEFINEDS is
- whether all defined symbols should be exported (the -unix linker
- option). SPECIAL_SECTIONS is set by this routine to csects with
- magic names like _end. */
+ be read only (the -btextro linker option). AUTO_EXPORT_FLAGS
+ is a mask of XCOFF_EXPALL and XCOFF_EXPFULL. SPECIAL_SECTIONS
+ is set by this routine to csects with magic names like _end. */
bfd_boolean
bfd_xcoff_size_dynamic_sections (bfd *output_bfd,
bfd_boolean gc,
int modtype,
bfd_boolean textro,
- bfd_boolean export_defineds,
+ unsigned int auto_export_flags,
asection **special_sections,
bfd_boolean rtld)
{
- struct xcoff_link_hash_entry *hentry;
asection *lsec;
struct xcoff_loader_info ldinfo;
int i;
ldinfo.failed = FALSE;
ldinfo.output_bfd = output_bfd;
ldinfo.info = info;
- ldinfo.export_defineds = export_defineds;
+ ldinfo.auto_export_flags = auto_export_flags;
ldinfo.ldsym_count = 0;
ldinfo.string_size = 0;
ldinfo.strings = NULL;
xcoff_hash_table (info)->file_align = file_align;
xcoff_hash_table (info)->textro = textro;
-
- hentry = NULL;
- if (entry != NULL)
- {
- hentry = xcoff_link_hash_lookup (xcoff_hash_table (info), entry,
- FALSE, FALSE, TRUE);
- if (hentry != NULL)
- hentry->flags |= XCOFF_ENTRY;
- }
+ xcoff_hash_table (info)->rtld = rtld;
/* __rtinit */
if (info->init_function || info->fini_function || rtld)
}
/* Garbage collect unused sections. */
- if (info->relocatable
- || ! gc
- || hentry == NULL
- || (hentry->root.type != bfd_link_hash_defined
- && hentry->root.type != bfd_link_hash_defweak))
+ if (info->relocatable || !gc)
{
gc = FALSE;
xcoff_hash_table (info)->gc = FALSE;
for (o = sub->sections; o != NULL; o = o->next)
{
- if ((o->flags & SEC_MARK) == 0)
+ /* We shouldn't unconditionaly mark the TOC section.
+ The output file should only have a TOC if either
+ (a) one of the input files did or (b) we end up
+ creating TOC references as part of the link process. */
+ if (o != xcoff_hash_table (info)->toc_section
+ && (o->flags & SEC_MARK) == 0)
{
if (! xcoff_mark (info, o))
goto error_return;
}
else
{
- if (! xcoff_mark (info, hentry->root.u.def.section))
+ if (entry != NULL
+ && !xcoff_mark_symbol_by_name (info, entry, XCOFF_ENTRY))
goto error_return;
+ if (info->init_function != NULL
+ && !xcoff_mark_symbol_by_name (info, info->init_function, 0))
+ goto error_return;
+ if (info->fini_function != NULL
+ && !xcoff_mark_symbol_by_name (info, info->fini_function, 0))
+ goto error_return;
+ if (auto_export_flags != 0)
+ {
+ xcoff_link_hash_traverse (xcoff_hash_table (info),
+ xcoff_mark_auto_exports, &ldinfo);
+ if (ldinfo.failed)
+ goto error_return;
+ }
xcoff_sweep (info);
xcoff_hash_table (info)->gc = TRUE;
}
goto error_return;
}
- /* Now that we've done garbage collection, figure out the contents
- of the .debug section. */
+ /* Now that we've done garbage collection, decide which symbols to keep,
+ and figure out the contents of the .debug section. */
debug_strtab = xcoff_hash_table (info)->debug_strtab;
for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
{
asection *subdeb;
bfd_size_type symcount;
- unsigned long *debug_index;
+ long *debug_index;
asection **csectpp;
+ unsigned int *lineno_counts;
+ struct xcoff_link_hash_entry **sym_hash;
bfd_byte *esym, *esymend;
bfd_size_type symesz;
- if (sub->xvec != info->hash->creator)
- continue;
- subdeb = bfd_get_section_by_name (sub, ".debug");
- if (subdeb == NULL || subdeb->size == 0)
+ if (sub->xvec != info->output_bfd->xvec)
continue;
- if (info->strip == strip_all
- || info->strip == strip_debugger
- || info->discard == discard_all)
- {
- subdeb->size = 0;
- continue;
- }
+ if ((sub->flags & DYNAMIC) != 0
+ && !info->static_link)
+ continue;
if (! _bfd_coff_get_external_symbols (sub))
goto error_return;
symcount = obj_raw_syment_count (sub);
- debug_index = bfd_zalloc (sub, symcount * sizeof (unsigned long));
+ debug_index = bfd_zalloc (sub, symcount * sizeof (long));
if (debug_index == NULL)
goto error_return;
xcoff_data (sub)->debug_indices = debug_index;
- /* Grab the contents of the .debug section. We use malloc and
- copy the names into the debug stringtab, rather than
- bfd_alloc, because I expect that, when linking many files
- together, many of the strings will be the same. Storing the
- strings in the hash table should save space in this case. */
- if (! bfd_malloc_and_get_section (sub, subdeb, &debug_contents))
- goto error_return;
+ if (info->strip == strip_all
+ || info->strip == strip_debugger
+ || info->discard == discard_all)
+ /* We're stripping all debugging information, so there's no need
+ to read SUB's .debug section. */
+ subdeb = NULL;
+ else
+ {
+ /* Grab the contents of SUB's .debug section, if any. */
+ subdeb = bfd_get_section_by_name (sub, ".debug");
+ if (subdeb != NULL && subdeb->size > 0)
+ {
+ /* We use malloc and copy the names into the debug
+ stringtab, rather than bfd_alloc, because I expect
+ that, when linking many files together, many of the
+ strings will be the same. Storing the strings in the
+ hash table should save space in this case. */
+ if (!bfd_malloc_and_get_section (sub, subdeb, &debug_contents))
+ goto error_return;
+ }
+ }
csectpp = xcoff_data (sub)->csects;
+ lineno_counts = xcoff_data (sub)->lineno_counts;
+ sym_hash = obj_xcoff_sym_hashes (sub);
+ symesz = bfd_coff_symesz (sub);
+ esym = (bfd_byte *) obj_coff_external_syms (sub);
+ esymend = esym + symcount * symesz;
- /* Dynamic object do not have csectpp's. */
- if (NULL != csectpp)
+ while (esym < esymend)
{
- symesz = bfd_coff_symesz (sub);
- esym = (bfd_byte *) obj_coff_external_syms (sub);
- esymend = esym + symcount * symesz;
+ struct internal_syment sym;
+ union internal_auxent aux;
+ asection *csect;
+ const char *name;
+ int keep_p;
- while (esym < esymend)
+ bfd_coff_swap_sym_in (sub, esym, &sym);
+
+ /* Read in the csect information, if any. */
+ if (CSECT_SYM_P (sym.n_sclass))
{
- struct internal_syment sym;
+ BFD_ASSERT (sym.n_numaux > 0);
+ bfd_coff_swap_aux_in (sub, esym + symesz * sym.n_numaux,
+ sym.n_type, sym.n_sclass,
+ sym.n_numaux - 1, sym.n_numaux, &aux);
+ }
- bfd_coff_swap_sym_in (sub, (void *) esym, (void *) &sym);
+ /* If this symbol's name is stored in the debug section,
+ get a pointer to it. */
+ if (debug_contents != NULL
+ && sym._n._n_n._n_zeroes == 0
+ && bfd_coff_symname_in_debug (sub, &sym))
+ name = (const char *) debug_contents + sym._n._n_n._n_offset;
+ else
+ name = NULL;
- *debug_index = (unsigned long) -1;
+ /* Decide whether to copy this symbol to the output file. */
+ csect = *csectpp;
+ keep_p = xcoff_keep_symbol_p (info, sub, &sym, &aux,
+ *sym_hash, csect, name);
+ if (keep_p < 0)
+ return FALSE;
- if (sym._n._n_n._n_zeroes == 0
- && *csectpp != NULL
- && (! gc
- || ((*csectpp)->flags & SEC_MARK) != 0
- || *csectpp == bfd_abs_section_ptr)
- && bfd_coff_symname_in_debug (sub, &sym))
+ if (!keep_p)
+ /* Use a debug_index of -2 to record that a symbol should
+ be stripped. */
+ *debug_index = -2;
+ else
+ {
+ /* See whether we should store the symbol name in the
+ output .debug section. */
+ if (name != NULL)
{
- char *name;
bfd_size_type indx;
- name = (char *) debug_contents + sym._n._n_n._n_offset;
indx = _bfd_stringtab_add (debug_strtab, name, TRUE, TRUE);
if (indx == (bfd_size_type) -1)
goto error_return;
*debug_index = indx;
}
-
- esym += (sym.n_numaux + 1) * symesz;
- csectpp += sym.n_numaux + 1;
- debug_index += sym.n_numaux + 1;
+ else
+ *debug_index = -1;
+ if (*sym_hash != 0)
+ (*sym_hash)->flags |= XCOFF_ALLOCATED;
+ if (*lineno_counts > 0)
+ csect->output_section->lineno_count += *lineno_counts;
}
+
+ esym += (sym.n_numaux + 1) * symesz;
+ csectpp += sym.n_numaux + 1;
+ sym_hash += sym.n_numaux + 1;
+ lineno_counts += sym.n_numaux + 1;
+ debug_index += sym.n_numaux + 1;
}
- free (debug_contents);
- debug_contents = NULL;
+ if (debug_contents)
+ {
+ free (debug_contents);
+ debug_contents = NULL;
- /* Clear the size of subdeb, so that it is not included directly
- in the output file. */
- subdeb->size = 0;
+ /* Clear the size of subdeb, so that it is not included directly
+ in the output file. */
+ subdeb->size = 0;
+ }
if (! info->keep_memory)
{
struct xcoff_link_hash_entry **sym_hash;
struct internal_syment *isymp;
asection **csectpp;
- unsigned long *debug_index;
+ unsigned int *lineno_counts;
+ long *debug_index;
long *indexp;
unsigned long output_index;
bfd_byte *outsym;
if (! _bfd_coff_get_external_symbols (input_bfd))
return FALSE;
+ /* Make one pass over the symbols and assign indices to symbols that
+ we have decided to keep. Also use create .loader symbol information
+ and update information in hash table entries. */
esym = (bfd_byte *) obj_coff_external_syms (input_bfd);
esym_end = esym + obj_raw_syment_count (input_bfd) * isymesz;
sym_hash = obj_xcoff_sym_hashes (input_bfd);
isymp = finfo->internal_syms;
indexp = finfo->sym_indices;
output_index = syment_base;
- outsym = finfo->outsyms;
- incls = 0;
- oline = NULL;
-
while (esym < esym_end)
{
- struct internal_syment isym;
union internal_auxent aux;
int smtyp = 0;
- bfd_boolean skip;
- bfd_boolean require;
int add;
bfd_coff_swap_sym_in (input_bfd, (void *) esym, (void *) isymp);
- /* If this is a C_EXT or C_HIDEXT symbol, we need the csect
- information. */
- if (isymp->n_sclass == C_EXT || isymp->n_sclass == C_HIDEXT)
+ /* Read in the csect information, if any. */
+ if (CSECT_SYM_P (isymp->n_sclass))
{
BFD_ASSERT (isymp->n_numaux > 0);
bfd_coff_swap_aux_in (input_bfd,
smtyp = SMTYP_SMTYP (aux.x_csect.x_smtyp);
}
- /* Make a copy of *isymp so that the relocate_section function
- always sees the original values. This is more reliable than
- always recomputing the symbol value even if we are stripping
- the symbol. */
- isym = *isymp;
-
/* If this symbol is in the .loader section, swap out the
.loader symbol information. If this is an external symbol
reference to a defined symbol, though, then wait until we get
to the definition. */
- if (isym.n_sclass == C_EXT
+ if (EXTERN_SYM_P (isymp->n_sclass)
&& *sym_hash != NULL
&& (*sym_hash)->ldsym != NULL
- && (smtyp != XTY_ER
- || (*sym_hash)->root.type == bfd_link_hash_undefined))
+ && xcoff_final_definition_p (input_bfd, *sym_hash, *csectpp))
{
struct xcoff_link_hash_entry *h;
struct internal_ldsym *ldsym;
h = *sym_hash;
ldsym = h->ldsym;
- if (isym.n_scnum > 0)
+ if (isymp->n_scnum > 0)
{
ldsym->l_scnum = (*csectpp)->output_section->target_index;
- ldsym->l_value = (isym.n_value
+ ldsym->l_value = (isymp->n_value
+ (*csectpp)->output_section->vma
+ (*csectpp)->output_offset
- (*csectpp)->vma);
}
else
{
- ldsym->l_scnum = isym.n_scnum;
- ldsym->l_value = isym.n_value;
+ ldsym->l_scnum = isymp->n_scnum;
+ ldsym->l_value = isymp->n_value;
}
ldsym->l_smtype = smtyp;
ldsym->l_smtype |= L_EXPORT;
if ((h->flags & XCOFF_ENTRY) != 0)
ldsym->l_smtype |= L_ENTRY;
+ if (isymp->n_sclass == C_AIX_WEAKEXT)
+ ldsym->l_smtype |= L_WEAK;
ldsym->l_smclas = aux.x_csect.x_smclas;
}
}
- *indexp = -1;
-
- skip = FALSE;
- require = FALSE;
- add = 1 + isym.n_numaux;
-
- /* If we are skipping this csect, we want to skip this symbol. */
- if (*csectpp == NULL)
- skip = TRUE;
-
- /* If we garbage collected this csect, we want to skip this
- symbol. */
- if (! skip
- && xcoff_hash_table (finfo->info)->gc
- && ((*csectpp)->flags & SEC_MARK) == 0
- && *csectpp != bfd_abs_section_ptr)
- skip = TRUE;
-
- /* An XCOFF linker always skips C_STAT symbols. */
- if (! skip
- && isymp->n_sclass == C_STAT)
- skip = TRUE;
-
- /* We skip all but the first TOC anchor. */
- if (! skip
- && isymp->n_sclass == C_HIDEXT
- && aux.x_csect.x_smclas == XMC_TC0)
- {
- if (finfo->toc_symindx != -1)
- skip = TRUE;
- else
- {
- bfd_vma tocval, tocend;
- bfd *inp;
-
- tocval = ((*csectpp)->output_section->vma
- + (*csectpp)->output_offset
- + isym.n_value
- - (*csectpp)->vma);
-
- /* We want to find out if tocval is a good value to use
- as the TOC anchor--that is, whether we can access all
- of the TOC using a 16 bit offset from tocval. This
- test assumes that the TOC comes at the end of the
- output section, as it does in the default linker
- script. */
- tocend = ((*csectpp)->output_section->vma
- + (*csectpp)->output_section->size);
- for (inp = finfo->info->input_bfds;
- inp != NULL;
- inp = inp->link_next)
- {
-
- for (o = inp->sections; o != NULL; o = o->next)
- if (strcmp (o->name, ".tocbss") == 0)
- {
- bfd_vma new_toc_end;
- new_toc_end = (o->output_section->vma
- + o->output_offset
- + o->size);
- if (new_toc_end > tocend)
- tocend = new_toc_end;
- }
-
- }
-
- if (tocval + 0x10000 < tocend)
- {
- (*_bfd_error_handler)
- (_("TOC overflow: 0x%lx > 0x10000; try -mminimal-toc when compiling"),
- (unsigned long) (tocend - tocval));
- bfd_set_error (bfd_error_file_too_big);
- return FALSE;
- }
-
- if (tocval + 0x8000 < tocend)
- {
- bfd_vma tocadd;
+ add = 1 + isymp->n_numaux;
- tocadd = tocend - (tocval + 0x8000);
- tocval += tocadd;
- isym.n_value += tocadd;
- }
+ if (*debug_index == -2)
+ /* We've decided to strip this symbol. */
+ *indexp = -1;
+ else
+ {
+ /* Assign the next unused index to this symbol. */
+ *indexp = output_index;
- finfo->toc_symindx = output_index;
- xcoff_data (finfo->output_bfd)->toc = tocval;
- xcoff_data (finfo->output_bfd)->sntoc =
- (*csectpp)->output_section->target_index;
- require = TRUE;
+ if (EXTERN_SYM_P (isymp->n_sclass))
+ {
+ BFD_ASSERT (*sym_hash != NULL);
+ (*sym_hash)->indx = output_index;
+ }
+ /* If this is a symbol in the TOC which we may have merged
+ (class XMC_TC), remember the symbol index of the TOC
+ symbol. */
+ if (isymp->n_sclass == C_HIDEXT
+ && aux.x_csect.x_smclas == XMC_TC
+ && *sym_hash != NULL)
+ {
+ BFD_ASSERT (((*sym_hash)->flags & XCOFF_SET_TOC) == 0);
+ BFD_ASSERT ((*sym_hash)->toc_section != NULL);
+ (*sym_hash)->u.toc_indx = output_index;
}
- }
- /* If we are stripping all symbols, we want to skip this one. */
- if (! skip
- && finfo->info->strip == strip_all)
- skip = TRUE;
-
- /* We can skip resolved external references. */
- if (! skip
- && isym.n_sclass == C_EXT
- && smtyp == XTY_ER
- && (*sym_hash)->root.type != bfd_link_hash_undefined)
- skip = TRUE;
-
- /* We can skip common symbols if they got defined somewhere
- else. */
- if (! skip
- && isym.n_sclass == C_EXT
- && smtyp == XTY_CM
- && ((*sym_hash)->root.type != bfd_link_hash_common
- || (*sym_hash)->root.u.c.p->section != *csectpp)
- && ((*sym_hash)->root.type != bfd_link_hash_defined
- || (*sym_hash)->root.u.def.section != *csectpp))
- skip = TRUE;
-
- /* Skip local symbols if we are discarding them. */
- if (! skip
- && finfo->info->discard == discard_all
- && isym.n_sclass != C_EXT
- && (isym.n_sclass != C_HIDEXT
- || smtyp != XTY_SD))
- skip = TRUE;
-
- /* If we stripping debugging symbols, and this is a debugging
- symbol, then skip it. */
- if (! skip
- && finfo->info->strip == strip_debugger
- && isym.n_scnum == N_DEBUG)
- skip = TRUE;
-
- /* If some symbols are stripped based on the name, work out the
- name and decide whether to skip this symbol. We don't handle
- this correctly for symbols whose names are in the .debug
- section; to get it right we would need a new bfd_strtab_hash
- function to return the string given the index. */
- if (! skip
- && (finfo->info->strip == strip_some
- || finfo->info->discard == discard_l)
- && (debug_index == NULL || *debug_index == (unsigned long) -1))
- {
- const char *name;
- char buf[SYMNMLEN + 1];
+ output_index += add;
+ }
- name = _bfd_coff_internal_syment_name (input_bfd, &isym, buf);
+ esym += add * isymesz;
+ isymp += add;
+ csectpp += add;
+ sym_hash += add;
+ debug_index += add;
+ ++indexp;
+ for (--add; add > 0; --add)
+ *indexp++ = -1;
+ }
- if (name == NULL)
- return FALSE;
+ /* Now write out the symbols that we decided to keep. */
- if ((finfo->info->strip == strip_some
- && (bfd_hash_lookup (finfo->info->keep_hash, name, FALSE,
- FALSE) == NULL))
- || (finfo->info->discard == discard_l
- && (isym.n_sclass != C_EXT
- && (isym.n_sclass != C_HIDEXT
- || smtyp != XTY_SD))
- && bfd_is_local_label_name (input_bfd, name)))
- skip = TRUE;
- }
+ esym = (bfd_byte *) obj_coff_external_syms (input_bfd);
+ esym_end = esym + obj_raw_syment_count (input_bfd) * isymesz;
+ isymp = finfo->internal_syms;
+ indexp = finfo->sym_indices;
+ csectpp = xcoff_data (input_bfd)->csects;
+ lineno_counts = xcoff_data (input_bfd)->lineno_counts;
+ debug_index = xcoff_data (input_bfd)->debug_indices;
+ outsym = finfo->outsyms;
+ incls = 0;
+ oline = NULL;
+ while (esym < esym_end)
+ {
+ int add;
- /* We can not skip the first TOC anchor. */
- if (skip
- && require
- && finfo->info->strip != strip_all)
- skip = FALSE;
+ add = 1 + isymp->n_numaux;
- /* We now know whether we are to skip this symbol or not. */
- if (! skip)
+ if (*indexp < 0)
+ esym += add * isymesz;
+ else
{
- /* Adjust the symbol in order to output it. */
+ struct internal_syment isym;
+ int i;
+ /* Adjust the symbol in order to output it. */
+ isym = *isymp;
if (isym._n._n_n._n_zeroes == 0
&& isym._n._n_n._n_offset != 0)
{
/* This symbol has a long name. Enter it in the string
table we are building. If *debug_index != -1, the
name has already been entered in the .debug section. */
- if (debug_index != NULL && *debug_index != (unsigned long) -1)
+ if (*debug_index >= 0)
isym._n._n_n._n_offset = *debug_index;
else
{
}
}
- if (isym.n_sclass != C_BSTAT
- && isym.n_sclass != C_ESTAT
- && isym.n_sclass != C_DECL
- && isym.n_scnum > 0)
- {
- isym.n_scnum = (*csectpp)->output_section->target_index;
- isym.n_value += ((*csectpp)->output_section->vma
- + (*csectpp)->output_offset
- - (*csectpp)->vma);
- }
-
/* The value of a C_FILE symbol is the symbol index of the
next C_FILE symbol. The value of the last C_FILE symbol
is -1. We try to get this right, below, just before we
if (isym.n_sclass == C_FILE)
{
if (finfo->last_file_index != -1
- && finfo->last_file.n_value != (bfd_vma) output_index)
+ && finfo->last_file.n_value != (bfd_vma) *indexp)
{
/* We must correct the value of the last C_FILE entry. */
- finfo->last_file.n_value = output_index;
+ finfo->last_file.n_value = *indexp;
if ((bfd_size_type) finfo->last_file_index >= syment_base)
{
/* The last C_FILE symbol is in this input file. */
}
}
- finfo->last_file_index = output_index;
+ finfo->last_file_index = *indexp;
finfo->last_file = isym;
}
isym.n_value = finfo->line_filepos;
++incls;
}
-
- /* Output the symbol. */
-
- bfd_coff_swap_sym_out (output_bfd, (void *) &isym, (void *) outsym);
-
- *indexp = output_index;
-
- if (isym.n_sclass == C_EXT)
- {
- long indx;
- struct xcoff_link_hash_entry *h;
-
- indx = ((esym - (bfd_byte *) obj_coff_external_syms (input_bfd))
- / isymesz);
- h = obj_xcoff_sym_hashes (input_bfd)[indx];
- BFD_ASSERT (h != NULL);
- h->indx = output_index;
- }
-
- /* If this is a symbol in the TOC which we may have merged
- (class XMC_TC), remember the symbol index of the TOC
- symbol. */
- if (isym.n_sclass == C_HIDEXT
- && aux.x_csect.x_smclas == XMC_TC
- && *sym_hash != NULL)
- {
- BFD_ASSERT (((*sym_hash)->flags & XCOFF_SET_TOC) == 0);
- BFD_ASSERT ((*sym_hash)->toc_section != NULL);
- (*sym_hash)->u.toc_indx = output_index;
- }
-
- output_index += add;
- outsym += add * osymesz;
- }
-
- esym += add * isymesz;
- isymp += add;
- csectpp += add;
- sym_hash += add;
- if (debug_index != NULL)
- debug_index += add;
- ++indexp;
- for (--add; add > 0; --add)
- *indexp++ = -1;
- }
-
- /* Fix up the aux entries and the C_BSTAT symbols. This must be
- done in a separate pass, because we don't know the correct symbol
- indices until we have already decided which symbols we are going
- to keep. */
-
- esym = (bfd_byte *) obj_coff_external_syms (input_bfd);
- esym_end = esym + obj_raw_syment_count (input_bfd) * isymesz;
- isymp = finfo->internal_syms;
- indexp = finfo->sym_indices;
- csectpp = xcoff_data (input_bfd)->csects;
- outsym = finfo->outsyms;
- while (esym < esym_end)
- {
- int add;
-
- add = 1 + isymp->n_numaux;
-
- if (*indexp < 0)
- esym += add * isymesz;
- else
- {
- int i;
-
- if (isymp->n_sclass == C_BSTAT)
+ /* The value of a C_BSTAT symbol is the symbol table
+ index of the containing csect. */
+ else if (isym.n_sclass == C_BSTAT)
{
- struct internal_syment isym;
-
bfd_vma indx;
- /* The value of a C_BSTAT symbol is the symbol table
- index of the containing csect. */
- bfd_coff_swap_sym_in (output_bfd, (void *) outsym, (void *) &isym);
indx = isym.n_value;
if (indx < obj_raw_syment_count (input_bfd))
{
isym.n_value = 0;
else
isym.n_value = symindx;
- bfd_coff_swap_sym_out (output_bfd, (void *) &isym,
- (void *) outsym);
}
}
+ else if (isym.n_sclass != C_ESTAT
+ && isym.n_sclass != C_DECL
+ && isym.n_scnum > 0)
+ {
+ isym.n_scnum = (*csectpp)->output_section->target_index;
+ isym.n_value += ((*csectpp)->output_section->vma
+ + (*csectpp)->output_offset
+ - (*csectpp)->vma);
+ }
+
+ /* Output the symbol. */
+ bfd_coff_swap_sym_out (output_bfd, (void *) &isym, (void *) outsym);
esym += isymesz;
outsym += osymesz;
aux.x_file.x_n.x_offset = STRING_SIZE_SIZE + indx;
}
}
- else if ((isymp->n_sclass == C_EXT
- || isymp->n_sclass == C_HIDEXT)
+ else if (CSECT_SYM_P (isymp->n_sclass)
&& i + 1 == isymp->n_numaux)
{
/* Copy over the line numbers, unless we are stripping
them. We do this on a symbol by symbol basis in
order to more easily handle garbage collection. */
- if ((isymp->n_sclass == C_EXT
- || isymp->n_sclass == C_HIDEXT)
+ if (CSECT_SYM_P (isymp->n_sclass)
&& i == 0
&& isymp->n_numaux > 1
&& ISFCN (isymp->n_type)
&& aux.x_sym.x_fcnary.x_fcn.x_lnnoptr != 0)
{
- if (finfo->info->strip != strip_none
- && finfo->info->strip != strip_some)
+ if (*lineno_counts == 0)
aux.x_sym.x_fcnary.x_fcn.x_lnnoptr = 0;
else
{
unsigned int enc_count;
bfd_signed_vma linoff;
struct internal_lineno lin;
+ bfd_byte *linp;
+ bfd_byte *linpend;
+ bfd_vma offset;
+ file_ptr pos;
+ bfd_size_type amt;
+ /* Read in the enclosing section's line-number
+ information, if we haven't already. */
o = *csectpp;
enclosing = xcoff_section_data (abfd, o)->enclosing;
enc_count = xcoff_section_data (abfd, o)->lineno_count;
if (oline != enclosing)
{
- file_ptr pos = enclosing->line_filepos;
- bfd_size_type amt = linesz * enc_count;
+ pos = enclosing->line_filepos;
+ amt = linesz * enc_count;
if (bfd_seek (input_bfd, pos, SEEK_SET) != 0
|| (bfd_bread (finfo->linenos, amt, input_bfd)
!= amt))
oline = enclosing;
}
+ /* Copy across the first entry, adjusting its
+ symbol index. */
linoff = (aux.x_sym.x_fcnary.x_fcn.x_lnnoptr
- enclosing->line_filepos);
-
- bfd_coff_swap_lineno_in (input_bfd,
- (void *) (finfo->linenos + linoff),
- (void *) &lin);
- if (lin.l_lnno != 0
- || ((bfd_size_type) lin.l_addr.l_symndx
- != ((esym
- - isymesz
- - ((bfd_byte *)
- obj_coff_external_syms (input_bfd)))
- / isymesz)))
- aux.x_sym.x_fcnary.x_fcn.x_lnnoptr = 0;
- else
+ linp = finfo->linenos + linoff;
+ bfd_coff_swap_lineno_in (input_bfd, linp, &lin);
+ lin.l_addr.l_symndx = *indexp;
+ bfd_coff_swap_lineno_out (output_bfd, &lin, linp);
+ linp += linesz;
+
+ /* Copy the other entries, adjusting their addresses. */
+ linpend = linp + *lineno_counts * linesz;
+ offset = (o->output_section->vma
+ + o->output_offset
+ - o->vma);
+ for (; linp < linpend; linp += linesz)
{
- bfd_byte *linpend, *linp;
- bfd_vma offset;
- bfd_size_type count;
-
- lin.l_addr.l_symndx = *indexp;
- bfd_coff_swap_lineno_out (output_bfd, (void *) &lin,
- (void *) (finfo->linenos
- + linoff));
-
- linpend = (finfo->linenos
- + enc_count * linesz);
- offset = (o->output_section->vma
- + o->output_offset
- - o->vma);
- for (linp = finfo->linenos + linoff + linesz;
- linp < linpend;
- linp += linesz)
- {
- bfd_coff_swap_lineno_in (input_bfd, (void *) linp,
- (void *) &lin);
- if (lin.l_lnno == 0)
- break;
- lin.l_addr.l_paddr += offset;
- bfd_coff_swap_lineno_out (output_bfd,
- (void *) &lin,
- (void *) linp);
- }
-
- count = (linp - (finfo->linenos + linoff)) / linesz;
+ bfd_coff_swap_lineno_in (input_bfd, linp, &lin);
+ lin.l_addr.l_paddr += offset;
+ bfd_coff_swap_lineno_out (output_bfd, &lin, linp);
+ }
- aux.x_sym.x_fcnary.x_fcn.x_lnnoptr =
- (o->output_section->line_filepos
+ /* Write out the entries we've just processed. */
+ pos = (o->output_section->line_filepos
+ o->output_section->lineno_count * linesz);
+ amt = linesz * *lineno_counts;
+ if (bfd_seek (output_bfd, pos, SEEK_SET) != 0
+ || bfd_bwrite (finfo->linenos + linoff,
+ amt, output_bfd) != amt)
+ return FALSE;
+ o->output_section->lineno_count += *lineno_counts;
- if (bfd_seek (output_bfd,
- aux.x_sym.x_fcnary.x_fcn.x_lnnoptr,
- SEEK_SET) != 0
- || (bfd_bwrite (finfo->linenos + linoff,
- linesz * count, output_bfd)
- != linesz * count))
- return FALSE;
-
- o->output_section->lineno_count += count;
+ /* Record the offset of the symbol's line numbers
+ in the output file. */
+ aux.x_sym.x_fcnary.x_fcn.x_lnnoptr = pos;
- if (incls > 0)
+ if (incls > 0)
+ {
+ struct internal_syment *iisp, *iispend;
+ long *iindp;
+ bfd_byte *oos;
+ bfd_vma range_start, range_end;
+ int iiadd;
+
+ /* Update any C_BINCL or C_EINCL symbols
+ that refer to a line number in the
+ range we just output. */
+ iisp = finfo->internal_syms;
+ iispend = iisp + obj_raw_syment_count (input_bfd);
+ iindp = finfo->sym_indices;
+ oos = finfo->outsyms;
+ range_start = enclosing->line_filepos + linoff;
+ range_end = range_start + *lineno_counts * linesz;
+ while (iisp < iispend)
{
- struct internal_syment *iisp, *iispend;
- long *iindp;
- bfd_byte *oos;
- int iiadd;
-
- /* Update any C_BINCL or C_EINCL symbols
- that refer to a line number in the
- range we just output. */
- iisp = finfo->internal_syms;
- iispend = (iisp
- + obj_raw_syment_count (input_bfd));
- iindp = finfo->sym_indices;
- oos = finfo->outsyms;
- while (iisp < iispend)
+ if (*iindp >= 0
+ && (iisp->n_sclass == C_BINCL
+ || iisp->n_sclass == C_EINCL)
+ && iisp->n_value >= range_start
+ && iisp->n_value < range_end)
{
- if (*iindp >= 0
- && (iisp->n_sclass == C_BINCL
- || iisp->n_sclass == C_EINCL)
- && ((bfd_size_type) iisp->n_value
- >= (bfd_size_type)(enclosing->line_filepos + linoff))
- && ((bfd_size_type) iisp->n_value
- < (enclosing->line_filepos
- + enc_count * linesz)))
- {
- struct internal_syment iis;
-
- bfd_coff_swap_sym_in (output_bfd,
- (void *) oos,
- (void *) &iis);
- iis.n_value =
- (iisp->n_value
- - enclosing->line_filepos
- - linoff
- + aux.x_sym.x_fcnary.x_fcn.x_lnnoptr);
- bfd_coff_swap_sym_out (output_bfd,
- (void *) &iis,
- (void *) oos);
- --incls;
- }
-
- iiadd = 1 + iisp->n_numaux;
- if (*iindp >= 0)
- oos += iiadd * osymesz;
- iisp += iiadd;
- iindp += iiadd;
+ struct internal_syment iis;
+
+ bfd_coff_swap_sym_in (output_bfd, oos, &iis);
+ iis.n_value = (iisp->n_value
+ - range_start
+ + pos);
+ bfd_coff_swap_sym_out (output_bfd,
+ &iis, oos);
+ --incls;
}
+
+ iiadd = 1 + iisp->n_numaux;
+ if (*iindp >= 0)
+ oos += iiadd * osymesz;
+ iisp += iiadd;
+ iindp += iiadd;
}
}
}
indexp += add;
isymp += add;
csectpp += add;
+ lineno_counts += add;
+ debug_index += add;
}
/* If we swapped out a C_FILE symbol, guess that the next C_FILE
{
struct xcoff_link_hash_entry *h = NULL;
struct internal_ldrel ldrel;
- bfd_boolean quiet;
*rel_hash = NULL;
}
}
- quiet = FALSE;
switch (irel->r_type)
{
default:
case R_NEG:
case R_RL:
case R_RLA:
+ if (h != NULL
+ && (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ && bfd_is_abs_section (h->root.u.def.section))
+ break;
/* This reloc needs to be copied into the .loader
section. */
ldrel.l_vaddr = irel->r_vaddr;
}
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"),
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"),
return 0;
}
+/* Return true if section SEC is a TOC section. */
+
+static inline bfd_boolean
+xcoff_toc_section_p (asection *sec)
+{
+ const char *name;
+
+ name = sec->name;
+ if (name[0] == '.' && name[1] == 't')
+ {
+ if (name[2] == 'c')
+ {
+ if (name[3] == '0' && name[4] == 0)
+ return TRUE;
+ if (name[3] == 0)
+ return TRUE;
+ }
+ if (name[2] == 'd' && name[3] == 0)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/* See if the link requires a TOC (it usually does!). If so, find a
+ good place to put the TOC anchor csect, and write out the associated
+ symbol. */
+
+static bfd_boolean
+xcoff_find_tc0 (bfd *output_bfd, struct xcoff_final_link_info *finfo)
+{
+ bfd_vma toc_start, toc_end, start, end, best_address;
+ asection *sec;
+ bfd *input_bfd;
+ int section_index;
+ struct internal_syment irsym;
+ union internal_auxent iraux;
+ file_ptr pos;
+ size_t size;
+
+ /* Set [TOC_START, TOC_END) to the range of the TOC. Record the
+ index of a csect at the beginning of the TOC. */
+ toc_start = ~(bfd_vma) 0;
+ toc_end = 0;
+ section_index = -1;
+ for (input_bfd = finfo->info->input_bfds;
+ input_bfd != NULL;
+ input_bfd = input_bfd->link_next)
+ for (sec = input_bfd->sections; sec != NULL; sec = sec->next)
+ if ((sec->flags & SEC_MARK) != 0 && xcoff_toc_section_p (sec))
+ {
+ start = sec->output_section->vma + sec->output_offset;
+ if (toc_start > start)
+ {
+ toc_start = start;
+ section_index = sec->output_section->target_index;
+ }
+
+ end = start + sec->size;
+ if (toc_end < end)
+ toc_end = end;
+ }
+
+ /* There's no need for a TC0 symbol if we don't have a TOC. */
+ if (toc_end < toc_start)
+ {
+ xcoff_data (output_bfd)->toc = toc_start;
+ return TRUE;
+ }
+
+ if (toc_end - toc_start < 0x8000)
+ /* Every TOC csect can be accessed from TOC_START. */
+ best_address = toc_start;
+ else
+ {
+ /* Find the lowest TOC csect that is still within range of TOC_END. */
+ best_address = toc_end;
+ for (input_bfd = finfo->info->input_bfds;
+ input_bfd != NULL;
+ input_bfd = input_bfd->link_next)
+ for (sec = input_bfd->sections; sec != NULL; sec = sec->next)
+ if ((sec->flags & SEC_MARK) != 0 && xcoff_toc_section_p (sec))
+ {
+ start = sec->output_section->vma + sec->output_offset;
+ if (start < best_address
+ && start + 0x8000 >= toc_end)
+ {
+ best_address = start;
+ section_index = sec->output_section->target_index;
+ }
+ }
+
+ /* Make sure that the start of the TOC is also within range. */
+ if (best_address > toc_start + 0x8000)
+ {
+ (*_bfd_error_handler)
+ (_("TOC overflow: 0x%lx > 0x10000; try -mminimal-toc "
+ "when compiling"),
+ (unsigned long) (toc_end - toc_start));
+ bfd_set_error (bfd_error_file_too_big);
+ return FALSE;
+ }
+ }
+
+ /* Record the chosen TOC value. */
+ finfo->toc_symindx = obj_raw_syment_count (output_bfd);
+ xcoff_data (output_bfd)->toc = best_address;
+ xcoff_data (output_bfd)->sntoc = section_index;
+
+ /* Fill out the TC0 symbol. */
+ if (!bfd_xcoff_put_symbol_name (output_bfd, finfo->strtab, &irsym, "TOC"))
+ return FALSE;
+ irsym.n_value = best_address;
+ irsym.n_scnum = section_index;
+ irsym.n_sclass = C_HIDEXT;
+ irsym.n_type = T_NULL;
+ irsym.n_numaux = 1;
+ bfd_coff_swap_sym_out (output_bfd, &irsym, finfo->outsyms);
+
+ /* Fill out the auxillary csect information. */
+ memset (&iraux, 0, sizeof iraux);
+ iraux.x_csect.x_smtyp = XTY_SD;
+ iraux.x_csect.x_smclas = XMC_TC0;
+ iraux.x_csect.x_scnlen.l = 0;
+ bfd_coff_swap_aux_out (output_bfd, &iraux, T_NULL, C_HIDEXT, 0, 1,
+ finfo->outsyms + bfd_coff_symesz (output_bfd));
+
+ /* Write the contents to the file. */
+ pos = obj_sym_filepos (output_bfd);
+ pos += obj_raw_syment_count (output_bfd) * bfd_coff_symesz (output_bfd);
+ size = 2 * bfd_coff_symesz (output_bfd);
+ if (bfd_seek (output_bfd, pos, SEEK_SET) != 0
+ || bfd_bwrite (finfo->outsyms, size, output_bfd) != size)
+ return FALSE;
+ obj_raw_syment_count (output_bfd) += 2;
+
+ return TRUE;
+}
+
/* Write out a non-XCOFF global symbol. */
static bfd_boolean
{
isym.n_value = 0;
isym.n_scnum = N_UNDEF;
- isym.n_sclass = C_EXT;
+ if (h->root.type == bfd_link_hash_undefweak
+ && C_WEAKEXT == C_AIX_WEAKEXT)
+ isym.n_sclass = C_WEAKEXT;
+ else
+ isym.n_sclass = C_EXT;
aux.x_csect.x_smtyp = XTY_ER;
}
else if ((h->root.type == bfd_link_hash_defined
BFD_ASSERT (bfd_is_abs_section (h->root.u.def.section));
isym.n_value = h->root.u.def.value;
isym.n_scnum = N_UNDEF;
- isym.n_sclass = C_EXT;
+ if (h->root.type == bfd_link_hash_undefweak
+ && C_WEAKEXT == C_AIX_WEAKEXT)
+ isym.n_sclass = C_WEAKEXT;
+ else
+ isym.n_sclass = C_EXT;
aux.x_csect.x_smtyp = XTY_ER;
}
else if (h->root.type == bfd_link_hash_defined
/* We just output an SD symbol. Now output an LD symbol. */
h->indx += 2;
- isym.n_sclass = C_EXT;
+ if (h->root.type == bfd_link_hash_undefweak
+ && C_WEAKEXT == C_AIX_WEAKEXT)
+ isym.n_sclass = C_WEAKEXT;
+ else
+ isym.n_sclass = C_EXT;
bfd_coff_swap_sym_out (output_bfd, (void *) &isym, (void *) outsym);
outsym += bfd_coff_symesz (output_bfd);
if (finfo.strtab == NULL)
goto error_return;
- /* Count the line number and relocation entries required for the
- output file. Determine a few maximum sizes. */
+ /* Count the relocation entries required for the output file.
+ (We've already counted the line numbers.) Determine a few
+ maximum sizes. */
max_contents_size = 0;
max_lineno_count = 0;
max_reloc_count = 0;
for (o = abfd->sections; o != NULL; o = o->next)
{
o->reloc_count = 0;
- o->lineno_count = 0;
for (p = o->map_head.link_order; p != NULL; p = p->next)
{
if (p->type == bfd_indirect_link_order)
the linker has decided to not include. */
sec->linker_mark = TRUE;
- if (info->strip == strip_none
- || info->strip == strip_some)
- o->lineno_count += sec->lineno_count;
-
o->reloc_count += sec->reloc_count;
if (sec->rawsize > max_contents_size)
max_contents_size = sec->rawsize;
if (sec->size > max_contents_size)
max_contents_size = sec->size;
- if (sec->lineno_count > max_lineno_count)
- max_lineno_count = sec->lineno_count;
if (coff_section_data (sec->owner, sec) != NULL
&& xcoff_section_data (sec->owner, sec) != NULL
&& (xcoff_section_data (sec->owner, sec)->lineno_count
goto error_return;
obj_raw_syment_count (abfd) = 0;
- xcoff_data (abfd)->toc = (bfd_vma) -1;
+
+ /* Find a TOC symbol, if we need one. */
+ if (!xcoff_find_tc0 (abfd, &finfo))
+ goto error_return;
/* We now know the position of everything in the file, except that
we don't know the size of the symbol table and therefore we don't