#include "coff/xcoff.h"
#include "libcoff.h"
#include "libxcoff.h"
+#include "libiberty.h"
/* This file holds the XCOFF linker code. */
} *toc_rel_hashes;
};
+/* Information that the XCOFF linker collects about an archive. */
+struct xcoff_archive_info
+{
+ /* The archive described by this entry. */
+ bfd *archive;
+
+ /* The import path and import filename to use when referring to
+ this archive in the .loader section. */
+ const char *imppath;
+ const char *impfile;
+
+ /* True if the archive contains a dynamic object. */
+ unsigned int contains_shared_object_p : 1;
+
+ /* True if the previous field is valid. */
+ unsigned int know_contains_shared_object_p : 1;
+};
+
+struct xcoff_link_hash_table
+{
+ struct bfd_link_hash_table root;
+
+ /* The .debug string hash table. We need to compute this while
+ reading the input files, so that we know how large the .debug
+ section will be before we assign section positions. */
+ struct bfd_strtab_hash *debug_strtab;
+
+ /* The .debug section we will use for the final output. */
+ asection *debug_section;
+
+ /* The .loader section we will use for the final output. */
+ asection *loader_section;
+
+ /* A count of non TOC relative relocs which will need to be
+ allocated in the .loader section. */
+ size_t ldrel_count;
+
+ /* The .loader section header. */
+ struct internal_ldhdr ldhdr;
+
+ /* The .gl section we use to hold global linkage code. */
+ asection *linkage_section;
+
+ /* The .tc section we use to hold toc entries we build for global
+ linkage code. */
+ asection *toc_section;
+
+ /* The .ds section we use to hold function descriptors which we
+ create for exported symbols. */
+ asection *descriptor_section;
+
+ /* The list of import files. */
+ struct xcoff_import_file *imports;
+
+ /* Required alignment of sections within the output file. */
+ unsigned long file_align;
+
+ /* Whether the .text section must be read-only. */
+ bfd_boolean textro;
+
+ /* Whether -brtl was specified. */
+ bfd_boolean rtld;
+
+ /* Whether garbage collection was done. */
+ bfd_boolean gc;
+
+ /* A linked list of symbols for which we have size information. */
+ struct xcoff_link_size_list
+ {
+ struct xcoff_link_size_list *next;
+ struct xcoff_link_hash_entry *h;
+ bfd_size_type size;
+ }
+ *size_list;
+
+ /* Information about archives. */
+ htab_t archive_info;
+
+ /* Magic sections: _text, _etext, _data, _edata, _end, end. */
+ asection *special_sections[XCOFF_NUMBER_OF_SPECIAL_SECTIONS];
+};
+
/* Information that we pass around while doing the final link step. */
struct xcoff_final_link_info
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. */
return ldhdr.l_nreloc;
}
\f
+/* Hash functions for xcoff_link_hash_table's archive_info. */
+
+static hashval_t
+xcoff_archive_info_hash (const void *data)
+{
+ const struct xcoff_archive_info *info;
+
+ info = (const struct xcoff_archive_info *) data;
+ return htab_hash_pointer (info->archive);
+}
+
+static int
+xcoff_archive_info_eq (const void *data1, const void *data2)
+{
+ const struct xcoff_archive_info *info1;
+ const struct xcoff_archive_info *info2;
+
+ info1 = (const struct xcoff_archive_info *) data1;
+ info2 = (const struct xcoff_archive_info *) data2;
+ return info1->archive == info2->archive;
+}
+
+/* Return information about archive ARCHIVE. Return NULL on error. */
+
+static struct xcoff_archive_info *
+xcoff_get_archive_info (struct bfd_link_info *info, bfd *archive)
+{
+ struct xcoff_link_hash_table *htab;
+ struct xcoff_archive_info *entryp, entry;
+ void **slot;
+
+ htab = xcoff_hash_table (info);
+ entry.archive = archive;
+ slot = htab_find_slot (htab->archive_info, &entry, INSERT);
+ if (!slot)
+ return NULL;
+
+ entryp = *slot;
+ if (!entryp)
+ {
+ entryp = bfd_zalloc (archive, sizeof (entry));
+ if (!entryp)
+ return NULL;
+
+ entryp->archive = archive;
+ *slot = entryp;
+ }
+ return entryp;
+}
+\f
/* Routine to create an entry in an XCOFF link hash table. */
static struct bfd_hash_entry *
ret->file_align = 0;
ret->textro = FALSE;
ret->gc = FALSE;
+ ret->archive_info = htab_create (37, xcoff_archive_info_hash,
+ xcoff_archive_info_eq, NULL);
memset (ret->special_sections, 0, sizeof ret->special_sections);
/* The linker will always generate a full a.out header. We need to
require_internal, internal_relocs);
}
\f
+/* Split FILENAME into an import path and an import filename,
+ storing them in *IMPPATH and *IMPFILE respectively. */
+
+bfd_boolean
+bfd_xcoff_split_import_path (bfd *abfd, const char *filename,
+ const char **imppath, const char **impfile)
+{
+ const char *basename;
+ size_t length;
+ char *path;
+
+ basename = lbasename (filename);
+ length = basename - filename;
+ if (length == 0)
+ /* The filename has no directory component, so use an empty path. */
+ *imppath = "";
+ else if (length == 1)
+ /* The filename is in the root directory. */
+ *imppath = "/";
+ else
+ {
+ /* Extract the (non-empty) directory part. Note that we don't
+ need to strip duplicate directory separators from any part
+ of the string; the native linker doesn't do that either. */
+ path = bfd_alloc (abfd, length);
+ if (path == NULL)
+ return FALSE;
+ memcpy (path, filename, length - 1);
+ path[length - 1] = 0;
+ *imppath = path;
+ }
+ *impfile = basename;
+ return TRUE;
+}
+
+/* Set ARCHIVE's import path as though its filename had been given
+ as FILENAME. */
+
+bfd_boolean
+bfd_xcoff_set_archive_import_path (struct bfd_link_info *info,
+ bfd *archive, const char *filename)
+{
+ struct xcoff_archive_info *archive_info;
+
+ archive_info = xcoff_get_archive_info (info, archive);
+ return (archive_info != NULL
+ && bfd_xcoff_split_import_path (archive, filename,
+ &archive_info->imppath,
+ &archive_info->impfile));
+}
+
+/* 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
+/* 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. */
const char *strings;
bfd_byte *elsym, *elsymend;
struct xcoff_import_file *n;
- const char *bname;
- const char *mname;
- const char *s;
unsigned int c;
struct xcoff_import_file **pp;
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. */
+ }
}
}
}
return FALSE;
n->next = NULL;
- /* For some reason, the path entry in the import file list for a
- shared object appears to always be empty. The file name is the
- base name. */
- n->path = "";
if (abfd->my_archive == NULL)
{
- bname = bfd_get_filename (abfd);
- mname = "";
+ if (!bfd_xcoff_split_import_path (abfd, abfd->filename,
+ &n->path, &n->file))
+ return FALSE;
+ n->member = "";
}
else
{
- bname = bfd_get_filename (abfd->my_archive);
- mname = bfd_get_filename (abfd);
+ struct xcoff_archive_info *archive_info;
+
+ archive_info = xcoff_get_archive_info (info, abfd->my_archive);
+ if (!archive_info->impfile)
+ {
+ if (!bfd_xcoff_split_import_path (archive_info->archive,
+ archive_info->archive->filename,
+ &archive_info->imppath,
+ &archive_info->impfile))
+ return FALSE;
+ }
+ n->path = archive_info->imppath;
+ n->file = archive_info->impfile;
+ n->member = bfd_get_filename (abfd);
}
- s = strrchr (bname, '/');
- if (s != NULL)
- bname = s + 1;
- n->file = bname;
- n->member = mname;
/* We start c at 1 because the first import file number is reserved
for LIBPATH. */
won't work if we're producing an XCOFF output file with no
XCOFF input files. FIXME. */
- if (xcoff_hash_table (info)->loader_section == NULL)
+ if (!info->relocatable
+ && xcoff_hash_table (info)->loader_section == NULL)
{
asection *lsec;
flagword flags = SEC_HAS_CONTENTS | SEC_IN_MEMORY;
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;
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);
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_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. */
+ /* 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;
}
}
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];
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;
}
}
\f
-/* Mark a symbol as not being garbage, including the section in which
- it is defined. */
-
-static inline bfd_boolean
-xcoff_mark_symbol (struct bfd_link_info *info, struct xcoff_link_hash_entry *h)
+bfd_boolean
+_bfd_xcoff_define_common_symbol (bfd *output_bfd ATTRIBUTE_UNUSED,
+ struct bfd_link_info *info ATTRIBUTE_UNUSED,
+ struct bfd_link_hash_entry *harg)
{
- if ((h->flags & XCOFF_MARK) != 0)
- return TRUE;
+ struct xcoff_link_hash_entry *h;
- h->flags |= XCOFF_MARK;
- if (h->root.type == bfd_link_hash_defined
- || h->root.type == bfd_link_hash_defweak)
+ if (!bfd_generic_define_common_symbol (output_bfd, info, harg))
+ return FALSE;
+
+ h = (struct xcoff_link_hash_entry *) harg;
+ h->flags |= XCOFF_DEF_REGULAR;
+ return TRUE;
+}
+\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] != '.')
{
- asection *hsec;
+ char *fnname;
+ struct xcoff_link_hash_entry *hfn;
+ bfd_size_type amt;
- hsec = h->root.u.def.section;
- if (! bfd_is_abs_section (hsec)
- && (hsec->flags & SEC_MARK) == 0)
+ 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))
{
- if (! xcoff_mark (info, hsec))
- return FALSE;
+ h->flags |= XCOFF_DESCRIPTOR;
+ h->descriptor = hfn;
+ hfn->descriptor = h;
}
}
+ return TRUE;
+}
+\f
+/* Return true if the given bfd contains at least one shared object. */
- if (h->toc_section != NULL
- && (h->toc_section->flags & SEC_MARK) == 0)
+static bfd_boolean
+xcoff_archive_contains_shared_object_p (struct bfd_link_info *info,
+ bfd *archive)
+{
+ struct xcoff_archive_info *archive_info;
+ bfd *member;
+
+ archive_info = xcoff_get_archive_info (info, archive);
+ if (!archive_info->know_contains_shared_object_p)
{
- if (! xcoff_mark (info, h->toc_section))
- return FALSE;
- }
+ member = bfd_openr_next_archived_file (archive, NULL);
+ while (member != NULL && (member->flags & DYNAMIC) == 0)
+ member = bfd_openr_next_archived_file (archive, member);
- return TRUE;
+ archive_info->contains_shared_object_p = (member != NULL);
+ archive_info->know_contains_shared_object_p = 1;
+ }
+ return archive_info->contains_shared_object_p;
}
-/* 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
- the number of relocs which need to be copied into the .loader
- section. */
+/* Symbol H qualifies for export by -bexpfull. Return true if it also
+ qualifies for export by -bexpall. */
static bfd_boolean
-xcoff_mark (struct bfd_link_info *info, asection *sec)
+xcoff_covered_by_expall_p (struct xcoff_link_hash_entry *h)
{
- if (bfd_is_abs_section (sec)
- || (sec->flags & SEC_MARK) != 0)
+ /* 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 bfd_link_info *info,
+ 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 (info, owner->my_archive))
+ return FALSE;
+ }
+
+ /* Otherwise, all symbols are exported by -bexpfull. */
+ if ((auto_export_flags & XCOFF_EXPFULL) != 0)
return TRUE;
- sec->flags |= SEC_MARK;
+ /* 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;
- if (sec->owner->xvec == info->output_bfd->xvec
- && coff_section_data (sec->owner, sec) != NULL
- && xcoff_section_data (sec->owner, sec) != NULL)
+ return FALSE;
+}
+\f
+/* Return true if relocation REL needs to be copied to the .loader section.
+ If REL is against a global symbol, H is that symbol, otherwise it
+ is null. */
+
+static bfd_boolean
+xcoff_need_ldrel_p (struct bfd_link_info *info, struct internal_reloc *rel,
+ struct xcoff_link_hash_entry *h)
+{
+ if (!xcoff_hash_table (info)->loader_section)
+ return FALSE;
+
+ switch (rel->r_type)
{
- struct xcoff_link_hash_entry **hp, **hpend;
- struct internal_reloc *rel, *relend;
+ case R_TOC:
+ case R_GL:
+ case R_TCL:
+ case R_TRL:
+ case R_TRLA:
+ /* We should never need a .loader reloc for a TOC-relative reloc. */
+ return FALSE;
- /* 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++)
+ default:
+ /* In this case, relocations against defined symbols can be resolved
+ statically. */
+ if (h == NULL
+ || h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak
+ || h->root.type == bfd_link_hash_common)
+ return FALSE;
+
+ /* We will always provide a local definition of function symbols,
+ even if we don't have one yet. */
+ if ((h->flags & XCOFF_CALLED) != 0)
+ return FALSE;
+
+ return TRUE;
+
+ case R_POS:
+ case R_NEG:
+ case R_RL:
+ case R_RLA:
+ /* Absolute relocations against absolute symbols can be
+ resolved statically. */
+ 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))
+ return FALSE;
+
+ return TRUE;
+ }
+}
+\f
+/* Mark a symbol as not being garbage, including the section in which
+ it is defined. */
+
+static inline bfd_boolean
+xcoff_mark_symbol (struct bfd_link_info *info, struct xcoff_link_hash_entry *h)
+{
+ if ((h->flags & XCOFF_MARK) != 0)
+ 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))
{
- struct xcoff_link_hash_entry *h;
+ /* This is a descriptor for a defined symbol, but the input
+ objects have not defined the descriptor itself. Fill in
+ the definition automatically.
- h = *hp;
- if (h != NULL
- && (h->flags & XCOFF_MARK) == 0)
+ 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_mark_symbol (info, h))
+ 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)
+ {
+ asection *hsec;
+
+ hsec = h->root.u.def.section;
+ if (! bfd_is_abs_section (hsec)
+ && (hsec->flags & SEC_MARK) == 0)
+ {
+ if (! xcoff_mark (info, hsec))
+ return FALSE;
+ }
+ }
+
+ if (h->toc_section != NULL
+ && (h->toc_section->flags & SEC_MARK) == 0)
+ {
+ if (! xcoff_mark (info, h->toc_section))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* 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
+ the number of relocs which need to be copied into the .loader
+ section. */
+
+static bfd_boolean
+xcoff_mark (struct bfd_link_info *info, asection *sec)
+{
+ if (bfd_is_abs_section (sec)
+ || (sec->flags & SEC_MARK) != 0)
+ return TRUE;
+
+ sec->flags |= SEC_MARK;
+
+ 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 **syms;
+ struct internal_reloc *rel, *relend;
+ asection **csects;
+ unsigned long i, first, last;
+
+ /* Mark all the symbols in this section. */
+ 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
section. */
- switch (rel->r_type)
+ if (xcoff_need_ldrel_p (info, rel, h))
{
- default:
- if (h == NULL
- || 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))))
- break;
- /* Fall through. */
- case R_POS:
- case R_NEG:
- case R_RL:
- case R_RLA:
++xcoff_hash_table (info)->ldrel_count;
if (h != NULL)
h->flags |= XCOFF_LDREL;
- break;
- case R_TOC:
- case R_GL:
- case R_TCL:
- case R_TRL:
- case R_TRLA:
- /* We should never need a .loader reloc for a TOC
- relative reloc. */
- break;
}
}
|| 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;
+ /* Make sure we don't garbage collect this symbol. */
+ if (! xcoff_mark_symbol (info, h))
+ return FALSE;
/* If this is a function descriptor, make sure we don't garbage
collect the associated function code. We normally don't have to
return FALSE;
}
- h->flags |= XCOFF_REF_REGULAR | XCOFF_LDREL;
- ++xcoff_hash_table (info)->ldrel_count;
+ h->flags |= XCOFF_REF_REGULAR;
+ if (xcoff_hash_table (info)->loader_section)
+ {
+ h->flags |= XCOFF_LDREL;
+ ++xcoff_hash_table (info)->ldrel_count;
+ }
/* Mark the symbol to avoid garbage collection. */
if (! xcoff_mark_symbol (info, h))
return TRUE;
}
-/* Add a symbol to the .loader symbols, if necessary. */
+/* 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_build_ldsyms (struct xcoff_link_hash_entry *h, void * p)
+xcoff_mark_auto_exports (struct xcoff_link_hash_entry *h, void *data)
{
- struct xcoff_loader_info *ldinfo = (struct xcoff_loader_info *) p;
- bfd_size_type amt;
+ struct xcoff_loader_info *ldinfo;
- if (h->root.type == bfd_link_hash_warning)
- h = (struct xcoff_link_hash_entry *) h->root.u.i.link;
+ ldinfo = (struct xcoff_loader_info *) data;
+ if (xcoff_auto_export_p (ldinfo->info, h, ldinfo->auto_export_flags))
+ {
+ if (!xcoff_mark_symbol (ldinfo->info, h))
+ ldinfo->failed = TRUE;
+ }
+ return TRUE;
+}
- /* __rtinit, this symbol has special handling. */
- if (h->flags & XCOFF_RTINIT)
+/* 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;
- /* If this is a final link, and the symbol was defined as a common
- symbol in a regular object file, and there was no definition in
- any dynamic object, then the linker will have allocated space for
- the symbol in a common section but the XCOFF_DEF_REGULAR flag
- will not have been set. */
- if (h->root.type == bfd_link_hash_defined
- && (h->flags & XCOFF_DEF_REGULAR) == 0
- && (h->flags & XCOFF_REF_REGULAR) != 0
- && (h->flags & XCOFF_DEF_DYNAMIC) == 0
- && (bfd_is_abs_section (h->root.u.def.section)
- || (h->root.u.def.section->owner->flags & DYNAMIC) == 0))
- h->flags |= XCOFF_DEF_REGULAR;
-
- /* 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] != '.')
+ default:
+ abort ();
+ }
+}
+
+/* See if H should have a loader symbol associated with it. */
+
+static bfd_boolean
+xcoff_build_ldsym (struct xcoff_loader_info *ldinfo,
+ struct xcoff_link_hash_entry *h)
+{
+ bfd_size_type amt;
+
+ /* Warn if this symbol is exported but not defined. */
+ if ((h->flags & XCOFF_EXPORT) != 0
+ && (h->flags & XCOFF_WAS_UNDEFINED) != 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;
+ (*_bfd_error_handler)
+ (_("warning: attempt to export undefined symbol `%s'"),
+ h->root.root.string);
+ return TRUE;
+ }
- 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);
- }
- }
+ /* We need to add a symbol to the .loader section if it is mentioned
+ in a reloc which we are copying to the .loader section and it was
+ not defined or common, or if it is the entry point, or if it is
+ being exported. */
+ if (((h->flags & XCOFF_LDREL) == 0
+ || h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak
+ || h->root.type == bfd_link_hash_common)
+ && (h->flags & XCOFF_ENTRY) == 0
+ && (h->flags & XCOFF_EXPORT) == 0)
+ return TRUE;
- if (export)
- h->flags |= XCOFF_EXPORT;
+ /* We need to add this symbol to the .loader symbols. */
+
+ BFD_ASSERT (h->ldsym == NULL);
+ amt = sizeof (struct internal_ldsym);
+ h->ldsym = bfd_zalloc (ldinfo->output_bfd, amt);
+ if (h->ldsym == NULL)
+ {
+ ldinfo->failed = TRUE;
+ return FALSE;
+ }
+
+ if ((h->flags & XCOFF_IMPORT) != 0)
+ {
+ /* 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. */
+ h->ldindx = ldinfo->ldsym_count + 3;
+
+ ++ldinfo->ldsym_count;
+
+ if (! bfd_xcoff_put_ldsymbol_name (ldinfo->output_bfd, ldinfo,
+ h->ldsym, h->root.root.string))
+ return FALSE;
+
+ h->flags |= XCOFF_BUILT_LDSYM;
+ return TRUE;
+}
+
+/* An xcoff_htab_traverse callback that is called for each symbol
+ once garbage collection is complete. */
+
+static bfd_boolean
+xcoff_post_gc_symbol (struct xcoff_link_hash_entry *h, void * p)
+{
+ struct xcoff_loader_info *ldinfo = (struct xcoff_loader_info *) p;
+
+ if (h->root.type == bfd_link_hash_warning)
+ h = (struct xcoff_link_hash_entry *) h->root.u.i.link;
+
+ /* __rtinit, this symbol has special handling. */
+ if (h->flags & XCOFF_RTINIT)
+ return TRUE;
+
/* We don't want to garbage collect symbols which are not defined in
XCOFF files. This is a convenient place to mark them. */
if (xcoff_hash_table (ldinfo->info)->gc
!= 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))
- {
- 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;
- }
- }
+ /* Skip discarded symbols. */
+ if (xcoff_hash_table (ldinfo->info)->gc
+ && (h->flags & XCOFF_MARK) == 0)
+ return TRUE;
/* If this is still a common symbol, and it wasn't garbage
collected, we need to actually allocate space for it in the .bss
section. */
if (h->root.type == bfd_link_hash_common
- && (! xcoff_hash_table (ldinfo->info)->gc
- || (h->flags & XCOFF_MARK) != 0)
&& h->root.u.c.p->section->size == 0)
{
BFD_ASSERT (bfd_is_com_section (h->root.u.c.p->section));
h->root.u.c.p->section->size = h->root.u.c.size;
}
- /* We need to add a symbol to the .loader section if it is mentioned
- in a reloc which we are copying to the .loader section and it was
- not defined or common, or if it is the entry point, or if it is
- being exported. */
+ if (xcoff_hash_table (ldinfo->info)->loader_section)
+ {
+ if (xcoff_auto_export_p (ldinfo->info, h, ldinfo->auto_export_flags))
+ h->flags |= XCOFF_EXPORT;
- if (((h->flags & XCOFF_LDREL) == 0
- || h->root.type == bfd_link_hash_defined
- || h->root.type == bfd_link_hash_defweak
- || h->root.type == bfd_link_hash_common)
- && (h->flags & XCOFF_ENTRY) == 0
- && (h->flags & XCOFF_EXPORT) == 0)
+ if (!xcoff_build_ldsym (ldinfo, h))
+ return FALSE;
+ }
+
+ 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))
{
- h->ldsym = NULL;
- return TRUE;
+ if ((h->flags & XCOFF_ALLOCATED) != 0)
+ return 0;
+ if (!xcoff_final_definition_p (input_bfd, h, csect))
+ return 0;
}
- /* We don't need to add this symbol if we did garbage collection and
- we did not mark this symbol. */
- if (xcoff_hash_table (ldinfo->info)->gc
- && (h->flags & XCOFF_MARK) == 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)
{
- h->ldsym = NULL;
- return TRUE;
+ 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;
}
- /* We may have already processed this symbol due to the recursive
- call above. */
- if ((h->flags & XCOFF_BUILT_LDSYM) != 0)
- return TRUE;
+ return 1;
+}
- /* We need to add this symbol to the .loader symbols. */
+/* Lay out the .loader section, filling in the header and the import paths.
+ LIBPATH is as for bfd_xcoff_size_dynamic_sections. */
- BFD_ASSERT (h->ldsym == NULL);
- amt = sizeof (struct internal_ldsym);
- h->ldsym = bfd_zalloc (ldinfo->output_bfd, amt);
- if (h->ldsym == NULL)
+static bfd_boolean
+xcoff_build_loader_section (struct xcoff_loader_info *ldinfo,
+ const char *libpath)
+{
+ bfd *output_bfd;
+ struct xcoff_link_hash_table *htab;
+ struct internal_ldhdr *ldhdr;
+ struct xcoff_import_file *fl;
+ bfd_size_type stoff;
+ size_t impsize, impcount;
+ asection *lsec;
+ char *out;
+
+ /* Work out the size of the import file names. Each import file ID
+ consists of three null terminated strings: the path, the file
+ name, and the archive member name. The first entry in the list
+ of names is the path to use to find objects, which the linker has
+ passed in as the libpath argument. For some reason, the path
+ entry in the other import file names appears to always be empty. */
+ output_bfd = ldinfo->output_bfd;
+ htab = xcoff_hash_table (ldinfo->info);
+ impsize = strlen (libpath) + 3;
+ impcount = 1;
+ for (fl = htab->imports; fl != NULL; fl = fl->next)
{
- ldinfo->failed = TRUE;
- return FALSE;
+ ++impcount;
+ impsize += (strlen (fl->path)
+ + strlen (fl->file)
+ + strlen (fl->member)
+ + 3);
}
- if ((h->flags & XCOFF_IMPORT) != 0)
- h->ldsym->l_ifile = h->ldindx;
+ /* Set up the .loader section header. */
+ ldhdr = &htab->ldhdr;
+ ldhdr->l_version = bfd_xcoff_ldhdr_version(output_bfd);
+ ldhdr->l_nsyms = ldinfo->ldsym_count;
+ ldhdr->l_nreloc = htab->ldrel_count;
+ ldhdr->l_istlen = impsize;
+ ldhdr->l_nimpid = impcount;
+ ldhdr->l_impoff = (bfd_xcoff_ldhdrsz (output_bfd)
+ + ldhdr->l_nsyms * bfd_xcoff_ldsymsz (output_bfd)
+ + ldhdr->l_nreloc * bfd_xcoff_ldrelsz (output_bfd));
+ ldhdr->l_stlen = ldinfo->string_size;
+ stoff = ldhdr->l_impoff + impsize;
+ if (ldinfo->string_size == 0)
+ ldhdr->l_stoff = 0;
+ else
+ ldhdr->l_stoff = stoff;
- /* The first 3 symbol table indices are reserved to indicate the
- data, text and bss sections. */
- h->ldindx = ldinfo->ldsym_count + 3;
+ /* 64 bit elements to ldhdr
+ The swap out routine for 32 bit will ignore them.
+ Nothing fancy, symbols come after the header and relocs come
+ after symbols. */
+ ldhdr->l_symoff = bfd_xcoff_ldhdrsz (output_bfd);
+ ldhdr->l_rldoff = (bfd_xcoff_ldhdrsz (output_bfd)
+ + ldhdr->l_nsyms * bfd_xcoff_ldsymsz (output_bfd));
- ++ldinfo->ldsym_count;
+ /* We now know the final size of the .loader section. Allocate
+ space for it. */
+ lsec = htab->loader_section;
+ lsec->size = stoff + ldhdr->l_stlen;
+ lsec->contents = bfd_zalloc (output_bfd, lsec->size);
+ if (lsec->contents == NULL)
+ return FALSE;
+
+ /* Set up the header. */
+ bfd_xcoff_swap_ldhdr_out (output_bfd, ldhdr, lsec->contents);
+
+ /* Set up the import file names. */
+ out = (char *) lsec->contents + ldhdr->l_impoff;
+ strcpy (out, libpath);
+ out += strlen (libpath) + 1;
+ *out++ = '\0';
+ *out++ = '\0';
+ for (fl = htab->imports; fl != NULL; fl = fl->next)
+ {
+ const char *s;
+
+ s = fl->path;
+ while ((*out++ = *s++) != '\0')
+ ;
+ s = fl->file;
+ while ((*out++ = *s++) != '\0')
+ ;
+ s = fl->member;
+ while ((*out++ = *s++) != '\0')
+ ;
+ }
+
+ BFD_ASSERT ((bfd_size_type) ((bfd_byte *) out - lsec->contents) == stoff);
- if (! bfd_xcoff_put_ldsymbol_name (ldinfo->output_bfd, ldinfo,
- h->ldsym, h->root.root.string))
- return FALSE;
+ /* Set up the symbol string table. */
+ if (ldinfo->string_size > 0)
+ {
+ memcpy (out, ldinfo->strings, ldinfo->string_size);
+ free (ldinfo->strings);
+ ldinfo->strings = NULL;
+ }
- h->flags |= XCOFF_BUILT_LDSYM;
+ /* We can't set up the symbol table or the relocs yet, because we
+ don't yet know the final position of the various sections. The
+ .loader symbols are written out when the corresponding normal
+ symbols are written out in xcoff_link_input_bfd or
+ xcoff_write_global_symbol. The .loader relocs are written out
+ when the corresponding normal relocs are handled in
+ xcoff_link_input_bfd. */
return TRUE;
}
+
/* 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;
- size_t impsize, impcount;
- struct xcoff_import_file *fl;
- struct internal_ldhdr *ldhdr;
- bfd_size_type stoff;
- char *out;
asection *sec;
bfd *sub;
struct bfd_strtab_hash *debug_strtab;
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)
+ if (xcoff_hash_table (info)->loader_section
+ && (info->init_function || info->fini_function || rtld))
{
struct xcoff_link_hash_entry *hsym;
struct internal_ldsym *ldsym;
}
/* 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;
}
/* I'm not sure what to do in this bizarre case. */
return TRUE;
- xcoff_link_hash_traverse (xcoff_hash_table (info), xcoff_build_ldsyms,
+ xcoff_link_hash_traverse (xcoff_hash_table (info), xcoff_post_gc_symbol,
(void *) &ldinfo);
if (ldinfo.failed)
goto error_return;
- /* Work out the size of the import file names. Each import file ID
- consists of three null terminated strings: the path, the file
- name, and the archive member name. The first entry in the list
- of names is the path to use to find objects, which the linker has
- passed in as the libpath argument. For some reason, the path
- entry in the other import file names appears to always be empty. */
- impsize = strlen (libpath) + 3;
- impcount = 1;
- for (fl = xcoff_hash_table (info)->imports; fl != NULL; fl = fl->next)
- {
- ++impcount;
- impsize += (strlen (fl->path)
- + strlen (fl->file)
- + strlen (fl->member)
- + 3);
- }
-
- /* Set up the .loader section header. */
- ldhdr = &xcoff_hash_table (info)->ldhdr;
- ldhdr->l_version = bfd_xcoff_ldhdr_version(output_bfd);
- ldhdr->l_nsyms = ldinfo.ldsym_count;
- ldhdr->l_nreloc = xcoff_hash_table (info)->ldrel_count;
- ldhdr->l_istlen = impsize;
- ldhdr->l_nimpid = impcount;
- ldhdr->l_impoff = (bfd_xcoff_ldhdrsz(output_bfd)
- + ldhdr->l_nsyms * bfd_xcoff_ldsymsz(output_bfd)
- + ldhdr->l_nreloc * bfd_xcoff_ldrelsz(output_bfd));
- ldhdr->l_stlen = ldinfo.string_size;
- stoff = ldhdr->l_impoff + impsize;
- if (ldinfo.string_size == 0)
- ldhdr->l_stoff = 0;
- else
- ldhdr->l_stoff = stoff;
-
- /* 64 bit elements to ldhdr
- The swap out routine for 32 bit will ignore them.
- Nothing fancy, symbols come after the header and relocs come
- after symbols. */
- ldhdr->l_symoff = bfd_xcoff_ldhdrsz (output_bfd);
- ldhdr->l_rldoff = (bfd_xcoff_ldhdrsz (output_bfd)
- + ldhdr->l_nsyms * bfd_xcoff_ldsymsz (output_bfd));
-
- /* We now know the final size of the .loader section. Allocate
- space for it. */
- lsec = xcoff_hash_table (info)->loader_section;
- lsec->size = stoff + ldhdr->l_stlen;
- lsec->contents = bfd_zalloc (output_bfd, lsec->size);
- if (lsec->contents == NULL)
+ if (xcoff_hash_table (info)->loader_section
+ && !xcoff_build_loader_section (&ldinfo, libpath))
goto error_return;
- /* Set up the header. */
- bfd_xcoff_swap_ldhdr_out (output_bfd, ldhdr, lsec->contents);
-
- /* Set up the import file names. */
- out = (char *) lsec->contents + ldhdr->l_impoff;
- strcpy (out, libpath);
- out += strlen (libpath) + 1;
- *out++ = '\0';
- *out++ = '\0';
- for (fl = xcoff_hash_table (info)->imports; fl != NULL; fl = fl->next)
- {
- const char *s;
-
- s = fl->path;
- while ((*out++ = *s++) != '\0')
- ;
- s = fl->file;
- while ((*out++ = *s++) != '\0')
- ;
- s = fl->member;
- while ((*out++ = *s++) != '\0')
- ;
- }
-
- BFD_ASSERT ((bfd_size_type) ((bfd_byte *) out - lsec->contents) == stoff);
-
- /* Set up the symbol string table. */
- if (ldinfo.string_size > 0)
- {
- memcpy (out, ldinfo.strings, ldinfo.string_size);
- free (ldinfo.strings);
- ldinfo.strings = NULL;
- }
-
- /* We can't set up the symbol table or the relocs yet, because we
- don't yet know the final position of the various sections. The
- .loader symbols are written out when the corresponding normal
- symbols are written out in xcoff_link_input_bfd or
- xcoff_write_global_symbol. The .loader relocs are written out
- when the corresponding normal relocs are handled in
- xcoff_link_input_bfd. */
-
/* Allocate space for the magic sections. */
sec = xcoff_hash_table (info)->linkage_section;
if (sec->size > 0)
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->output_bfd->xvec)
continue;
- subdeb = bfd_get_section_by_name (sub, ".debug");
- if (subdeb == NULL || subdeb->size == 0)
- 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)
{
return TRUE;
}
\f
+/* Return the section that defines H. Return null if no section does. */
+
+static asection *
+xcoff_symbol_section (struct xcoff_link_hash_entry *h)
+{
+ switch (h->root.type)
+ {
+ case bfd_link_hash_defined:
+ case bfd_link_hash_defweak:
+ return h->root.u.def.section;
+
+ case bfd_link_hash_common:
+ return h->root.u.c.p->section;
+
+ default:
+ return NULL;
+ }
+}
+
+/* Add a .loader relocation for input relocation IREL. If the loader
+ relocation should be against an output section, HSEC points to the
+ input section that IREL is against, otherwise HSEC is null. H is the
+ symbol that IREL is against, or null if it isn't against a global symbol.
+ REFERENCE_BFD is the bfd to use in error messages about the relocation. */
+
+static bfd_boolean
+xcoff_create_ldrel (bfd *output_bfd, struct xcoff_final_link_info *finfo,
+ asection *output_section, bfd *reference_bfd,
+ struct internal_reloc *irel, asection *hsec,
+ struct xcoff_link_hash_entry *h)
+{
+ struct internal_ldrel ldrel;
+
+ ldrel.l_vaddr = irel->r_vaddr;
+ if (hsec != NULL)
+ {
+ const char *secname;
+
+ secname = hsec->output_section->name;
+ if (strcmp (secname, ".text") == 0)
+ ldrel.l_symndx = 0;
+ else if (strcmp (secname, ".data") == 0)
+ ldrel.l_symndx = 1;
+ else if (strcmp (secname, ".bss") == 0)
+ ldrel.l_symndx = 2;
+ else
+ {
+ (*_bfd_error_handler)
+ (_("%B: loader reloc in unrecognized section `%s'"),
+ reference_bfd, secname);
+ bfd_set_error (bfd_error_nonrepresentable_section);
+ return FALSE;
+ }
+ }
+ else if (h != NULL)
+ {
+ if (h->ldindx < 0)
+ {
+ (*_bfd_error_handler)
+ (_("%B: `%s' in loader reloc but not loader sym"),
+ reference_bfd, h->root.root.string);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+ ldrel.l_symndx = h->ldindx;
+ }
+ else
+ ldrel.l_symndx = -(bfd_size_type) 1;
+
+ ldrel.l_rtype = (irel->r_size << 8) | irel->r_type;
+ ldrel.l_rsecnm = output_section->target_index;
+ if (xcoff_hash_table (finfo->info)->textro
+ && strcmp (output_section->name, ".text") == 0)
+ {
+ (*_bfd_error_handler)
+ (_("%B: loader reloc in read-only section %A"),
+ reference_bfd, output_section);
+ bfd_set_error (bfd_error_invalid_operation);
+ return FALSE;
+ }
+ bfd_xcoff_swap_ldrel_out (output_bfd, &ldrel, finfo->ldrel);
+ finfo->ldrel += bfd_xcoff_ldrelsz (output_bfd);
+ return TRUE;
+}
+
/* Link an input file into the linker output file. This function
handles all the sections and relocations of the input file at once. */
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;
+ sym_hash = obj_xcoff_sym_hashes (input_bfd);
+ 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);
- }
+ /* Make __rtinit C_HIDEXT rather than C_EXT. This avoids
+ multiple definition problems when linking a shared object
+ statically. (The native linker doesn't enter __rtinit into
+ the normal table at all, but having a local symbol can make
+ the objdump output easier to read.) */
+ if (isym.n_sclass == C_EXT
+ && *sym_hash
+ && ((*sym_hash)->flags & XCOFF_RTINIT) != 0)
+ isym.n_sclass = C_HIDEXT;
/* 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
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);
+
+ /* Copy the other entries, adjusting their addresses. */
+ linpend = linp + *lineno_counts * linesz;
+ offset = (o->output_section->vma
+ + o->output_offset
+ - o->vma);
+ for (linp += linesz; 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;
}
}
}
}
}
+ sym_hash += add;
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
for (; irel < irelend; irel++, rel_hash++)
{
struct xcoff_link_hash_entry *h = NULL;
- struct internal_ldrel ldrel;
- bfd_boolean quiet;
*rel_hash = NULL;
}
}
- quiet = FALSE;
- switch (irel->r_type)
+ if (xcoff_need_ldrel_p (finfo->info, irel, h))
{
- default:
- if (h == NULL
- || h->root.type == bfd_link_hash_defined
- || h->root.type == bfd_link_hash_defweak
- || h->root.type == bfd_link_hash_common)
- break;
- /* Fall through. */
- case R_POS:
- case R_NEG:
- case R_RL:
- case R_RLA:
- /* This reloc needs to be copied into the .loader
- section. */
- ldrel.l_vaddr = irel->r_vaddr;
- if (r_symndx == -1)
- ldrel.l_symndx = -(bfd_size_type ) 1;
- else if (h == NULL
- || (h->root.type == bfd_link_hash_defined
- || h->root.type == bfd_link_hash_defweak
- || h->root.type == bfd_link_hash_common))
- {
- asection *sec;
+ asection *sec;
- if (h == NULL)
- sec = xcoff_data (input_bfd)->csects[r_symndx];
- else if (h->root.type == bfd_link_hash_common)
- sec = h->root.u.c.p->section;
- else
- sec = h->root.u.def.section;
- sec = sec->output_section;
-
- if (strcmp (sec->name, ".text") == 0)
- ldrel.l_symndx = 0;
- else if (strcmp (sec->name, ".data") == 0)
- ldrel.l_symndx = 1;
- else if (strcmp (sec->name, ".bss") == 0)
- ldrel.l_symndx = 2;
- else
- {
- (*_bfd_error_handler)
- (_("%B: loader reloc in unrecognized section `%A'"),
- input_bfd, sec);
- bfd_set_error (bfd_error_nonrepresentable_section);
- return FALSE;
- }
- }
+ if (r_symndx == -1)
+ sec = NULL;
+ else if (h == NULL)
+ sec = xcoff_data (input_bfd)->csects[r_symndx];
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)
- {
- (*_bfd_error_handler)
- (_("%B: `%s' in loader reloc but not loader sym"),
- input_bfd,
- h->root.root.string);
- bfd_set_error (bfd_error_bad_value);
- return FALSE;
- }
- ldrel.l_symndx = h->ldindx;
- }
- ldrel.l_rtype = (irel->r_size << 8) | irel->r_type;
- ldrel.l_rsecnm = o->output_section->target_index;
- if (xcoff_hash_table (finfo->info)->textro
- && strcmp (o->output_section->name, ".text") == 0
- && ! quiet)
- {
- (*_bfd_error_handler)
- (_("%B: loader reloc in read-only section %A"),
- input_bfd, o->output_section);
- bfd_set_error (bfd_error_invalid_operation);
- return FALSE;
- }
- bfd_xcoff_swap_ldrel_out (output_bfd, &ldrel,
- finfo->ldrel);
-
- finfo->ldrel += bfd_xcoff_ldrelsz(output_bfd);
- break;
-
- case R_TOC:
- case R_GL:
- case R_TCL:
- case R_TRL:
- case R_TRLA:
- /* We should never need a .loader reloc for a TOC
- relative reloc. */
- break;
+ sec = xcoff_symbol_section (h);
+ if (!xcoff_create_ldrel (output_bfd, finfo,
+ o->output_section, input_bfd,
+ irel, sec, h))
+ return FALSE;
}
}
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
asection *osec;
int oindx;
struct internal_reloc *irel;
- struct internal_ldrel ldrel;
struct internal_syment irsym;
union internal_auxent iraux;
finfo->section_info[oindx].rel_hashes[osec->reloc_count] = NULL;
++osec->reloc_count;
- ldrel.l_vaddr = irel->r_vaddr;
- ldrel.l_symndx = h->ldindx;
- ldrel.l_rtype = (irel->r_size << 8) | R_POS;
- ldrel.l_rsecnm = oindx;
- bfd_xcoff_swap_ldrel_out (output_bfd, &ldrel, finfo->ldrel);
- finfo->ldrel += bfd_xcoff_ldrelsz(output_bfd);
+ if (!xcoff_create_ldrel (output_bfd, finfo, osec,
+ output_bfd, irel, NULL, h))
+ return FALSE;
/* We need to emit a symbol to define a csect which holds
the reloc. */
struct xcoff_link_hash_entry *hentry;
asection *esec;
struct internal_reloc *irel;
- struct internal_ldrel ldrel;
asection *tsec;
unsigned int reloc_size, byte_size;
finfo->section_info[oindx].rel_hashes[osec->reloc_count] = NULL;
++osec->reloc_count;
- ldrel.l_vaddr = irel->r_vaddr;
- if (strcmp (esec->output_section->name, ".text") == 0)
- ldrel.l_symndx = 0;
- else if (strcmp (esec->output_section->name, ".data") == 0)
- ldrel.l_symndx = 1;
- else if (strcmp (esec->output_section->name, ".bss") == 0)
- ldrel.l_symndx = 2;
- else
- {
- (*_bfd_error_handler)
- (_("%s: loader reloc in unrecognized section `%s'"),
- bfd_get_filename (output_bfd),
- esec->output_section->name);
- bfd_set_error (bfd_error_nonrepresentable_section);
- return FALSE;
- }
- ldrel.l_rtype = (reloc_size << 8) | R_POS;
- ldrel.l_rsecnm = oindx;
- bfd_xcoff_swap_ldrel_out (output_bfd, &ldrel, finfo->ldrel);
- finfo->ldrel += bfd_xcoff_ldrelsz(output_bfd);
+ if (!xcoff_create_ldrel (output_bfd, finfo, osec,
+ output_bfd, irel, esec, NULL))
+ return FALSE;
/* There are three items to write out,
the address of the code
finfo->section_info[oindx].rel_hashes[osec->reloc_count] = NULL;
++osec->reloc_count;
- ldrel.l_vaddr = irel->r_vaddr;
- if (strcmp (tsec->output_section->name, ".text") == 0)
- ldrel.l_symndx = 0;
- else if (strcmp (tsec->output_section->name, ".data") == 0)
- ldrel.l_symndx = 1;
- else if (strcmp (tsec->output_section->name, ".bss") == 0)
- ldrel.l_symndx = 2;
- else
- {
- (*_bfd_error_handler)
- (_("%s: loader reloc in unrecognized section `%s'"),
- bfd_get_filename (output_bfd),
- tsec->output_section->name);
- bfd_set_error (bfd_error_nonrepresentable_section);
- return FALSE;
- }
- ldrel.l_rtype = (reloc_size << 8) | R_POS;
- ldrel.l_rsecnm = oindx;
- bfd_xcoff_swap_ldrel_out (output_bfd, &ldrel, finfo->ldrel);
- finfo->ldrel += bfd_xcoff_ldrelsz(output_bfd);
+ if (!xcoff_create_ldrel (output_bfd, finfo, osec,
+ output_bfd, irel, tsec, NULL))
+ return FALSE;
}
if (h->indx >= 0 || finfo->info->strip == strip_all)
{
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);
bfd_vma addend;
struct internal_reloc *irel;
struct xcoff_link_hash_entry **rel_hash_ptr;
- struct internal_ldrel ldrel;
if (link_order->type == bfd_section_reloc_link_order)
/* We need to somehow locate a symbol in the right section. The
return TRUE;
}
- if (h->root.type == bfd_link_hash_common)
- {
- hsec = h->root.u.c.p->section;
- hval = 0;
- }
- else if (h->root.type == bfd_link_hash_defined
- || h->root.type == bfd_link_hash_defweak)
- {
- hsec = h->root.u.def.section;
- hval = h->root.u.def.value;
- }
+ hsec = xcoff_symbol_section (h);
+ if (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ hval = h->root.u.def.value;
else
- {
- hsec = NULL;
- hval = 0;
- }
+ hval = 0;
addend = link_order->u.reloc.p->addend;
if (hsec != NULL)
++output_section->reloc_count;
/* Now output the reloc to the .loader section. */
-
- ldrel.l_vaddr = irel->r_vaddr;
-
- if (hsec != NULL)
- {
- const char *secname;
-
- secname = hsec->output_section->name;
-
- if (strcmp (secname, ".text") == 0)
- ldrel.l_symndx = 0;
- else if (strcmp (secname, ".data") == 0)
- ldrel.l_symndx = 1;
- else if (strcmp (secname, ".bss") == 0)
- ldrel.l_symndx = 2;
- else
- {
- (*_bfd_error_handler)
- (_("%s: loader reloc in unrecognized section `%s'"),
- bfd_get_filename (output_bfd), secname);
- bfd_set_error (bfd_error_nonrepresentable_section);
- return FALSE;
- }
- }
- else
+ if (xcoff_hash_table (finfo->info)->loader_section)
{
- if (h->ldindx < 0)
- {
- (*_bfd_error_handler)
- (_("%s: `%s' in loader reloc but not loader sym"),
- bfd_get_filename (output_bfd),
- h->root.root.string);
- bfd_set_error (bfd_error_bad_value);
- return FALSE;
- }
- ldrel.l_symndx = h->ldindx;
+ if (!xcoff_create_ldrel (output_bfd, finfo, output_section,
+ output_bfd, irel, hsec, h))
+ return FALSE;
}
- ldrel.l_rtype = (irel->r_size << 8) | irel->r_type;
- ldrel.l_rsecnm = output_section->target_index;
- bfd_xcoff_swap_ldrel_out (output_bfd, &ldrel, finfo->ldrel);
- finfo->ldrel += bfd_xcoff_ldrelsz(output_bfd);
-
return TRUE;
}
finfo.contents = NULL;
finfo.external_relocs = NULL;
- finfo.ldsym = (xcoff_hash_table (info)->loader_section->contents
- + bfd_xcoff_ldhdrsz (abfd));
- finfo.ldrel = (xcoff_hash_table (info)->loader_section->contents
- + bfd_xcoff_ldhdrsz(abfd)
- + (xcoff_hash_table (info)->ldhdr.l_nsyms
- * bfd_xcoff_ldsymsz(abfd)));
+ if (xcoff_hash_table (info)->loader_section)
+ {
+ finfo.ldsym = (xcoff_hash_table (info)->loader_section->contents
+ + bfd_xcoff_ldhdrsz (abfd));
+ finfo.ldrel = (xcoff_hash_table (info)->loader_section->contents
+ + bfd_xcoff_ldhdrsz (abfd)
+ + (xcoff_hash_table (info)->ldhdr.l_nsyms
+ * bfd_xcoff_ldsymsz (abfd)));
+ }
+ else
+ {
+ finfo.ldsym = NULL;
+ finfo.ldrel = NULL;
+ }
xcoff_data (abfd)->coff.link_info = info;
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
}
/* Write out the loader section contents. */
- BFD_ASSERT ((bfd_byte *) finfo.ldrel
- == (xcoff_hash_table (info)->loader_section->contents
- + xcoff_hash_table (info)->ldhdr.l_impoff));
o = xcoff_hash_table (info)->loader_section;
- if (! bfd_set_section_contents (abfd, o->output_section, o->contents,
- (file_ptr) o->output_offset, o->size))
- goto error_return;
+ if (o)
+ {
+ BFD_ASSERT ((bfd_byte *) finfo.ldrel
+ == (xcoff_hash_table (info)->loader_section->contents
+ + xcoff_hash_table (info)->ldhdr.l_impoff));
+ if (!bfd_set_section_contents (abfd, o->output_section, o->contents,
+ (file_ptr) o->output_offset, o->size))
+ goto error_return;
+ }
/* Write out the magic sections. */
o = xcoff_hash_table (info)->linkage_section;