/* POWER/PowerPC XCOFF linker support.
Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
- 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+ 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
Written by Ian Lance Taylor <ian@cygnus.com>, Cygnus Support.
This file is part of BFD, the Binary File Descriptor library.
#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 *base;
+ size_t length;
+ char *path;
+
+ base = lbasename (filename);
+ length = base - 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 = base;
+ 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 (filename_cmp ((*pp)->path, imppath) == 0
+ && filename_cmp ((*pp)->file, impfile) == 0
+ && filename_cmp ((*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;
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
smtyp = SMTYP_SMTYP (aux.x_csect.x_smtyp);
- flags = BSF_GLOBAL;
section = NULL;
value = 0;
set_toc = NULL;
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;
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);
|| sym._n._n_n._n_offset == 0)
copy = TRUE;
+ /* Ignore global linkage code when linking statically. */
+ if (info->static_link
+ && (smtyp == XTY_SD || smtyp == XTY_LD)
+ && aux.x_csect.x_smclas == XMC_GL)
+ {
+ section = bfd_und_section_ptr;
+ value = 0;
+ }
+
/* The AIX linker appears to only detect multiple symbol
definitions when there is a reference to the symbol. If
a symbol is defined multiple times, and the only
We also have to handle the case of statically linking a
shared object, which will cause symbol redefinitions,
although this is an easier case to detect. */
-
- if (info->output_bfd->xvec == abfd->xvec)
+ else if (info->output_bfd->xvec == abfd->xvec)
{
if (! bfd_is_und_section (section))
*sym_hash = xcoff_link_hash_lookup (xcoff_hash_table (info),
&& ! bfd_is_com_section (section))
{
/* This is a second definition of a defined symbol. */
- if ((abfd->flags & DYNAMIC) != 0
- && ((*sym_hash)->smclas != XMC_GL
- || aux.x_csect.x_smclas == XMC_GL
- || ((*sym_hash)->root.u.def.section->owner->flags
- & DYNAMIC) == 0))
- {
- /* The new symbol is from a shared library, and
- either the existing symbol is not global
- linkage code or this symbol is global linkage
- code. If the existing symbol is global
- linkage code and the new symbol is not, then
- we want to use the new symbol. */
- section = bfd_und_section_ptr;
- value = 0;
- }
- else if (((*sym_hash)->root.u.def.section->owner->flags
- & DYNAMIC) != 0)
+ 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,
{
int flag;
- if (smtyp == XTY_ER || smtyp == XTY_CM)
+ if (smtyp == XTY_ER
+ || smtyp == XTY_CM
+ || section == bfd_und_section_ptr)
flag = XCOFF_REF_REGULAR;
else
flag = XCOFF_DEF_REGULAR;
static bfd_boolean
xcoff_link_check_dynamic_ar_symbols (bfd *abfd,
struct bfd_link_info *info,
- bfd_boolean *pneeded)
+ bfd_boolean *pneeded,
+ bfd **subsbfd)
{
asection *lsec;
bfd_byte *contents;
&& (((struct xcoff_link_hash_entry *) h)->flags
& XCOFF_DEF_DYNAMIC) == 0)
{
- if (! (*info->callbacks->add_archive_element) (info, abfd, name))
+ if (!(*info->callbacks
+ ->add_archive_element) (info, abfd, name, subsbfd))
return FALSE;
*pneeded = TRUE;
return TRUE;
static bfd_boolean
xcoff_link_check_ar_symbols (bfd *abfd,
struct bfd_link_info *info,
- bfd_boolean *pneeded)
+ bfd_boolean *pneeded,
+ bfd **subsbfd)
{
bfd_size_type symesz;
bfd_byte *esym;
if ((abfd->flags & DYNAMIC) != 0
&& ! info->static_link
&& info->output_bfd->xvec == abfd->xvec)
- return xcoff_link_check_dynamic_ar_symbols (abfd, info, pneeded);
+ return xcoff_link_check_dynamic_ar_symbols (abfd, info, pneeded, subsbfd);
symesz = bfd_coff_symesz (abfd);
esym = (bfd_byte *) obj_coff_external_syms (abfd);
bfd_coff_swap_sym_in (abfd, (void *) esym, (void *) &sym);
- if (sym.n_sclass == C_EXT && sym.n_scnum != N_UNDEF)
+ if (EXTERN_SYM_P (sym.n_sclass) && sym.n_scnum != N_UNDEF)
{
const char *name;
char buf[SYMNMLEN + 1];
|| (((struct xcoff_link_hash_entry *) h)->flags
& XCOFF_DEF_DYNAMIC) == 0))
{
- if (! (*info->callbacks->add_archive_element) (info, abfd, name))
+ if (!(*info->callbacks
+ ->add_archive_element) (info, abfd, name, subsbfd))
return FALSE;
*pneeded = TRUE;
return TRUE;
struct bfd_link_info *info,
bfd_boolean *pneeded)
{
- if (! _bfd_coff_get_external_symbols (abfd))
+ bfd_boolean keep_syms_p;
+ bfd *oldbfd;
+
+ keep_syms_p = (obj_coff_external_syms (abfd) != NULL);
+ if (!_bfd_coff_get_external_symbols (abfd))
return FALSE;
- if (! xcoff_link_check_ar_symbols (abfd, info, pneeded))
+ oldbfd = abfd;
+ if (!xcoff_link_check_ar_symbols (abfd, info, pneeded, &abfd))
return FALSE;
if (*pneeded)
{
- if (! xcoff_link_add_symbols (abfd, info))
+ /* Potentially, the add_archive_element hook may have set a
+ substitute BFD for us. */
+ if (abfd != oldbfd)
+ {
+ if (!keep_syms_p
+ && !_bfd_coff_free_symbols (oldbfd))
+ return FALSE;
+ 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))
+ if (!_bfd_coff_free_symbols (abfd))
return FALSE;
}
}
}
\f
+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)
+{
+ struct xcoff_link_hash_entry *h;
+
+ 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. */
}
return TRUE;
}
-
-/* H is an imported symbol. Set the import module's path, file and member
- to IMPATH, IMPFILE and IMPMEMBER respectively. All three are null if
- no specific import module is specified. */
+\f
+/* Return true if the given bfd contains at least one shared object. */
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)
+xcoff_archive_contains_shared_object_p (struct bfd_link_info *info,
+ bfd *archive)
{
- unsigned int c;
- struct xcoff_import_file **pp;
+ struct xcoff_archive_info *archive_info;
+ bfd *member;
- /* 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
+ archive_info = xcoff_get_archive_info (info, archive);
+ if (!archive_info->know_contains_shared_object_p)
{
- /* 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);
+ member = bfd_openr_next_archived_file (archive, NULL);
+ while (member != NULL && (member->flags & DYNAMIC) == 0)
+ member = bfd_openr_next_archived_file (archive, member);
- 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;
+ archive_info->contains_shared_object_p = (member != NULL);
+ archive_info->know_contains_shared_object_p = 1;
}
- return TRUE;
+ return archive_info->contains_shared_object_p;
}
-\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;
+/* Symbol H qualifies for export by -bexpfull. Return true if it also
+ qualifies for export by -bexpall. */
- h->flags |= XCOFF_MARK;
+static bfd_boolean
+xcoff_covered_by_expall_p (struct xcoff_link_hash_entry *h)
+{
+ /* Exclude symbols beginning with '_'. */
+ if (h->root.root.string[0] == '_')
+ return FALSE;
+
+ /* Exclude archive members that would otherwise be unreferenced. */
+ if ((h->flags & XCOFF_MARK) == 0
+ && (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ && h->root.u.def.section->owner != NULL
+ && h->root.u.def.section->owner->my_archive != NULL)
+ return FALSE;
+
+ return TRUE;
+}
+
+/* Return true if symbol H qualifies for the forms of automatic export
+ specified by AUTO_EXPORT_FLAGS. */
+
+static bfd_boolean
+xcoff_auto_export_p (struct 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;
+
+ /* Despite its name, -bexpall exports most but not all symbols. */
+ if ((auto_export_flags & XCOFF_EXPALL) != 0
+ && xcoff_covered_by_expall_p (h))
+ return TRUE;
+
+ return FALSE;
+}
+\f
+/* 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)
+ {
+ 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;
+
+ 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. */
/* We handle writing out the contents of the descriptor in
xcoff_write_global_symbol. */
}
+ else if (info->static_link)
+ /* We can't get a symbol value dynamically, so just assume
+ that it's undefined. */
+ h->flags |= XCOFF_WAS_UNDEFINED;
else if ((h->flags & XCOFF_CALLED) != 0)
{
/* This is a function symbol for which we need to create
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
/* 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
- /* We will always provide a local definition of
- function symbols. */
- || (h->flags & XCOFF_CALLED) != 0)
- break;
- /* Fall through. */
- case R_POS:
- case R_NEG:
- case R_RL:
- case R_RLA:
- if (h != NULL
- && (h->root.type == bfd_link_hash_defined
- || h->root.type == bfd_link_hash_defweak)
- && bfd_is_abs_section (h->root.u.def.section))
- break;
++xcoff_hash_table (info)->ldrel_count;
if (h != NULL)
h->flags |= XCOFF_LDREL;
- 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;
}
}
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;
}
+/* An xcoff_link_hash_traverse callback for which DATA points to an
+ xcoff_loader_info. Mark all symbols that should be automatically
+ exported. */
+
+static bfd_boolean
+xcoff_mark_auto_exports (struct xcoff_link_hash_entry *h, void *data)
+{
+ struct xcoff_loader_info *ldinfo;
+
+ ldinfo = (struct xcoff_loader_info *) data;
+ if (xcoff_auto_export_p (ldinfo->info, h, ldinfo->auto_export_flags))
+ {
+ if (!xcoff_mark_symbol (ldinfo->info, h))
+ ldinfo->failed = TRUE;
+ }
+ return TRUE;
+}
+
/* Add a symbol to the .loader symbols, if necessary. */
/* INPUT_BFD has an external symbol associated with hash table entry H
}
}
+/* See if H should have a loader symbol associated with it. */
+
static bfd_boolean
-xcoff_build_ldsyms (struct xcoff_link_hash_entry *h, void * p)
+xcoff_build_ldsym (struct xcoff_loader_info *ldinfo,
+ struct xcoff_link_hash_entry *h)
{
- struct xcoff_loader_info *ldinfo = (struct xcoff_loader_info *) p;
bfd_size_type amt;
- 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;
-
- /* 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] != '.')
- {
- bfd_boolean export;
-
- /* We don't export a symbol which is being defined by an object
- included from an archive which contains a shared object. The
- rationale is that if an archive contains both an unshared and
- a shared object, then there must be some reason that the
- unshared object is unshared, and we don't want to start
- providing a shared version of it. In particular, this solves
- a bug involving the _savefNN set of functions. gcc will call
- those functions without providing a slot to restore the TOC,
- so it is essential that these functions be linked in directly
- and not from a shared object, which means that a shared
- object which also happens to link them in must not export
- them. This is confusing, but I haven't been able to think of
- a different approach. Note that the symbols can, of course,
- be exported explicitly. */
- export = TRUE;
- if ((h->root.type == bfd_link_hash_defined
- || h->root.type == bfd_link_hash_defweak)
- && h->root.u.def.section->owner != NULL
- && h->root.u.def.section->owner->my_archive != NULL)
- {
- bfd *arbfd, *member;
-
- arbfd = h->root.u.def.section->owner->my_archive;
- member = bfd_openr_next_archived_file (arbfd, NULL);
- while (member != NULL)
- {
- if ((member->flags & DYNAMIC) != 0)
- {
- export = FALSE;
- break;
- }
- member = bfd_openr_next_archived_file (arbfd, member);
- }
- }
-
- if (export)
- h->flags |= XCOFF_EXPORT;
- }
-
- /* 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
- && (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->xvec
- != ldinfo->info->output_bfd->xvec)))
- h->flags |= XCOFF_MARK;
-
- /* If this symbol is exported, but not defined, we need to try to
- define it. */
+ /* Warn if this symbol is exported but not defined. */
if ((h->flags & XCOFF_EXPORT) != 0
&& (h->flags & XCOFF_WAS_UNDEFINED) != 0)
{
(*_bfd_error_handler)
(_("warning: attempt to export undefined symbol `%s'"),
h->root.root.string);
- h->ldsym = NULL;
return TRUE;
}
- /* If this is still a common symbol, and it wasn't garbage
- 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 (((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)
- {
- h->ldsym = NULL;
- return TRUE;
- }
-
- /* 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)
- {
- h->ldsym = NULL;
- return TRUE;
- }
-
- /* We may have already processed this symbol due to the recursive
- call above. */
- if ((h->flags & XCOFF_BUILT_LDSYM) != 0)
return TRUE;
/* We need to add this symbol to the .loader symbols. */
}
if ((h->flags & XCOFF_IMPORT) != 0)
- h->ldsym->l_ifile = h->ldindx;
+ {
+ /* Give imported descriptors class XMC_DS rather than XMC_UA. */
+ if ((h->flags & XCOFF_DESCRIPTOR) != 0)
+ h->smclas = XMC_DS;
+ h->ldsym->l_ifile = h->ldindx;
+ }
/* The first 3 symbol table indices are reserved to indicate the
data, text and bss sections. */
return 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
+ && (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->xvec
+ != ldinfo->info->output_bfd->xvec)))
+ h->flags |= XCOFF_MARK;
+
+ /* 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
+ && 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;
+ }
+
+ 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 (!xcoff_build_ldsym (ldinfo, h))
+ return FALSE;
+ }
return TRUE;
}
return 0;
/* Discard symbols that are defined elsewhere. */
- if (isym->n_sclass == C_EXT)
+ if (EXTERN_SYM_P (isym->n_sclass))
{
if ((h->flags & XCOFF_ALLOCATED) != 0)
return 0;
/* If we're discarding local symbols, check whether ISYM is local. */
smtyp = SMTYP_SMTYP (aux->x_csect.x_smtyp);
if (info->discard == discard_all
- && isym->n_sclass != C_EXT
+ && !EXTERN_SYM_P (isym->n_sclass)
&& (isym->n_sclass != C_HIDEXT || smtyp != XTY_SD))
return 0;
return 0;
if (info->discard == discard_l
- && isym->n_sclass != C_EXT
+ && !EXTERN_SYM_P (isym->n_sclass)
&& (isym->n_sclass != C_HIDEXT || smtyp != XTY_SD)
&& bfd_is_local_label_name (input_bfd, name))
return 0;
return 1;
}
+/* Lay out the .loader section, filling in the header and the import paths.
+ LIBPATH is as for bfd_xcoff_size_dynamic_sections. */
+
+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)
+ {
+ ++impcount;
+ impsize += (strlen (fl->path)
+ + strlen (fl->file)
+ + strlen (fl->member)
+ + 3);
+ }
+
+ /* 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;
+
+ /* 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 = 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);
+
+ /* 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. */
+
+ 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;
+ int i;
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)->textro = textro;
xcoff_hash_table (info)->rtld = rtld;
- 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;
- }
-
/* __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;
}
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)
bfd_coff_swap_sym_in (sub, esym, &sym);
- /* If this is a C_EXT or C_HIDEXT symbol, we need the csect
- information too. */
- if (sym.n_sclass == C_EXT || sym.n_sclass == C_HIDEXT)
+ /* Read in the csect information, if any. */
+ if (CSECT_SYM_P (sym.n_sclass))
{
BFD_ASSERT (sym.n_numaux > 0);
bfd_coff_swap_aux_in (sub, esym + symesz * sym.n_numaux,
abfd->format = bfd_object;
abfd->iostream = (void *) bim;
abfd->flags = BFD_IN_MEMORY;
+ abfd->iovec = &_bfd_memory_iovec;
abfd->direction = write_direction;
+ abfd->origin = 0;
abfd->where = 0;
if (! bfd_xcoff_generate_rtinit (abfd, init, fini, rtld))
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 *flinfo,
+ 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 (flinfo->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, flinfo->ldrel);
+ flinfo->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. */
static bfd_boolean
-xcoff_link_input_bfd (struct xcoff_final_link_info *finfo,
+xcoff_link_input_bfd (struct xcoff_final_link_info *flinfo,
bfd *input_bfd)
{
bfd *output_bfd;
/* We can just skip DYNAMIC files, unless this is a static link. */
if ((input_bfd->flags & DYNAMIC) != 0
- && ! finfo->info->static_link)
+ && ! flinfo->info->static_link)
return TRUE;
/* Move all the symbols to the output file. */
- output_bfd = finfo->output_bfd;
+ output_bfd = flinfo->output_bfd;
strings = NULL;
syment_base = obj_raw_syment_count (output_bfd);
isymesz = bfd_coff_symesz (input_bfd);
#define N_BTSHFT n_btshft
copy = FALSE;
- if (! finfo->info->keep_memory)
+ if (! flinfo->info->keep_memory)
copy = TRUE;
hash = TRUE;
if ((output_bfd->flags & BFD_TRADITIONAL_FORMAT) != 0)
sym_hash = obj_xcoff_sym_hashes (input_bfd);
csectpp = xcoff_data (input_bfd)->csects;
debug_index = xcoff_data (input_bfd)->debug_indices;
- isymp = finfo->internal_syms;
- indexp = finfo->sym_indices;
+ isymp = flinfo->internal_syms;
+ indexp = flinfo->sym_indices;
output_index = syment_base;
while (esym < esym_end)
{
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,
.loader symbol information. If this is an external symbol
reference to a defined symbol, though, then wait until we get
to the definition. */
- if (isymp->n_sclass == C_EXT
+ if (EXTERN_SYM_P (isymp->n_sclass)
&& *sym_hash != NULL
&& (*sym_hash)->ldsym != NULL
&& xcoff_final_definition_p (input_bfd, *sym_hash, *csectpp))
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;
ldsym->l_ifile = 0;
else
{
- BFD_ASSERT (impbfd->xvec == finfo->output_bfd->xvec);
+ BFD_ASSERT (impbfd->xvec == flinfo->output_bfd->xvec);
ldsym->l_ifile = xcoff_data (impbfd)->import_file_id;
}
}
ldsym->l_parm = 0;
BFD_ASSERT (h->ldindx >= 0);
- bfd_xcoff_swap_ldsym_out (finfo->output_bfd, ldsym,
- (finfo->ldsym
+ bfd_xcoff_swap_ldsym_out (flinfo->output_bfd, ldsym,
+ (flinfo->ldsym
+ ((h->ldindx - 3)
- * bfd_xcoff_ldsymsz (finfo->output_bfd))));
+ * bfd_xcoff_ldsymsz (flinfo->output_bfd))));
h->ldsym = NULL;
/* Fill in snentry now that we know the target_index. */
/* Assign the next unused index to this symbol. */
*indexp = output_index;
- if (isymp->n_sclass == C_EXT)
+ if (EXTERN_SYM_P (isymp->n_sclass))
{
BFD_ASSERT (*sym_hash != NULL);
(*sym_hash)->indx = output_index;
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;
+ sym_hash = obj_xcoff_sym_hashes (input_bfd);
+ isymp = flinfo->internal_syms;
+ indexp = flinfo->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;
+ outsym = flinfo->outsyms;
incls = 0;
oline = NULL;
while (esym < esym_end)
if (name == NULL)
return FALSE;
- indx = _bfd_stringtab_add (finfo->strtab, name, hash, copy);
+ indx = _bfd_stringtab_add (flinfo->strtab, name, hash, copy);
if (indx == (bfd_size_type) -1)
return FALSE;
isym._n._n_n._n_offset = STRING_SIZE_SIZE + indx;
}
}
+ /* 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
is -1. We try to get this right, below, just before we
have to write the symbol out twice. */
if (isym.n_sclass == C_FILE)
{
- if (finfo->last_file_index != -1
- && finfo->last_file.n_value != (bfd_vma) *indexp)
+ if (flinfo->last_file_index != -1
+ && flinfo->last_file.n_value != (bfd_vma) *indexp)
{
/* We must correct the value of the last C_FILE entry. */
- finfo->last_file.n_value = *indexp;
- if ((bfd_size_type) finfo->last_file_index >= syment_base)
+ flinfo->last_file.n_value = *indexp;
+ if ((bfd_size_type) flinfo->last_file_index >= syment_base)
{
/* The last C_FILE symbol is in this input file. */
bfd_coff_swap_sym_out (output_bfd,
- (void *) &finfo->last_file,
- (void *) (finfo->outsyms
- + ((finfo->last_file_index
+ (void *) &flinfo->last_file,
+ (void *) (flinfo->outsyms
+ + ((flinfo->last_file_index
- syment_base)
* osymesz)));
}
file_ptr pos;
bfd_coff_swap_sym_out (output_bfd,
- (void *) &finfo->last_file,
+ (void *) &flinfo->last_file,
(void *) outsym);
pos = obj_sym_filepos (output_bfd);
- pos += finfo->last_file_index * osymesz;
+ pos += flinfo->last_file_index * osymesz;
if (bfd_seek (output_bfd, pos, SEEK_SET) != 0
|| (bfd_bwrite (outsym, osymesz, output_bfd)
!= osymesz))
}
}
- finfo->last_file_index = *indexp;
- finfo->last_file = isym;
+ flinfo->last_file_index = *indexp;
+ flinfo->last_file = isym;
}
/* The value of a C_BINCL or C_EINCL symbol is a file offset
if (isym.n_sclass == C_BINCL
|| isym.n_sclass == C_EINCL)
{
- isym.n_value = finfo->line_filepos;
+ isym.n_value = flinfo->line_filepos;
++incls;
}
/* The value of a C_BSTAT symbol is the symbol table
{
long symindx;
- symindx = finfo->sym_indices[indx];
+ symindx = flinfo->sym_indices[indx];
if (symindx < 0)
isym.n_value = 0;
else
return FALSE;
}
filename = strings + aux.x_file.x_n.x_offset;
- indx = _bfd_stringtab_add (finfo->strtab, filename,
+ indx = _bfd_stringtab_add (flinfo->strtab, filename,
hash, copy);
if (indx == (bfd_size_type) -1)
return FALSE;
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)
{
{
long symindx;
- symindx = finfo->sym_indices[indx];
+ symindx = flinfo->sym_indices[indx];
if (symindx < 0)
{
aux.x_csect.x_scnlen.l = 0;
the index of the next symbol we are going
to include. I don't know if this is
entirely right. */
- while (finfo->sym_indices[indx] < 0
+ while (flinfo->sym_indices[indx] < 0
&& indx < obj_raw_syment_count (input_bfd))
++indx;
if (indx >= obj_raw_syment_count (input_bfd))
indx = output_index;
else
- indx = finfo->sym_indices[indx];
+ indx = flinfo->sym_indices[indx];
aux.x_sym.x_fcnary.x_fcn.x_endndx.l = indx;
}
{
long symindx;
- symindx = finfo->sym_indices[indx];
+ symindx = flinfo->sym_indices[indx];
if (symindx < 0)
aux.x_sym.x_tagndx.l = 0;
else
/* 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)
pos = enclosing->line_filepos;
amt = linesz * enc_count;
if (bfd_seek (input_bfd, pos, SEEK_SET) != 0
- || (bfd_bread (finfo->linenos, amt, input_bfd)
+ || (bfd_bread (flinfo->linenos, amt, input_bfd)
!= amt))
return FALSE;
oline = enclosing;
symbol index. */
linoff = (aux.x_sym.x_fcnary.x_fcn.x_lnnoptr
- enclosing->line_filepos);
- linp = finfo->linenos + linoff;
+ linp = flinfo->linenos + linoff;
bfd_coff_swap_lineno_in (input_bfd, linp, &lin);
lin.l_addr.l_symndx = *indexp;
bfd_coff_swap_lineno_out (output_bfd, &lin, linp);
- linp += linesz;
/* Copy the other entries, adjusting their addresses. */
linpend = linp + *lineno_counts * linesz;
offset = (o->output_section->vma
+ o->output_offset
- o->vma);
- for (; linp < linpend; linp += linesz)
+ for (linp += linesz; linp < linpend; linp += linesz)
{
bfd_coff_swap_lineno_in (input_bfd, linp, &lin);
lin.l_addr.l_paddr += offset;
+ o->output_section->lineno_count * linesz);
amt = linesz * *lineno_counts;
if (bfd_seek (output_bfd, pos, SEEK_SET) != 0
- || bfd_bwrite (finfo->linenos + linoff,
+ || bfd_bwrite (flinfo->linenos + linoff,
amt, output_bfd) != amt)
return FALSE;
o->output_section->lineno_count += *lineno_counts;
/* Update any C_BINCL or C_EINCL symbols
that refer to a line number in the
range we just output. */
- iisp = finfo->internal_syms;
+ iisp = flinfo->internal_syms;
iispend = iisp + obj_raw_syment_count (input_bfd);
- iindp = finfo->sym_indices;
- oos = finfo->outsyms;
+ iindp = flinfo->sym_indices;
+ oos = flinfo->outsyms;
range_start = enclosing->line_filepos + linoff;
range_end = range_start + *lineno_counts * linesz;
while (iisp < iispend)
}
}
+ sym_hash += add;
indexp += add;
isymp += add;
csectpp += add;
symbol will be the first symbol in the next input file. In the
normal case, this will save us from writing out the C_FILE symbol
again. */
- if (finfo->last_file_index != -1
- && (bfd_size_type) finfo->last_file_index >= syment_base)
+ if (flinfo->last_file_index != -1
+ && (bfd_size_type) flinfo->last_file_index >= syment_base)
{
- finfo->last_file.n_value = output_index;
- bfd_coff_swap_sym_out (output_bfd, (void *) &finfo->last_file,
- (void *) (finfo->outsyms
- + ((finfo->last_file_index - syment_base)
+ flinfo->last_file.n_value = output_index;
+ bfd_coff_swap_sym_out (output_bfd, (void *) &flinfo->last_file,
+ (void *) (flinfo->outsyms
+ + ((flinfo->last_file_index - syment_base)
* osymesz)));
}
/* Write the modified symbols to the output file. */
- if (outsym > finfo->outsyms)
+ if (outsym > flinfo->outsyms)
{
file_ptr pos = obj_sym_filepos (output_bfd) + syment_base * osymesz;
- bfd_size_type amt = outsym - finfo->outsyms;
+ bfd_size_type amt = outsym - flinfo->outsyms;
if (bfd_seek (output_bfd, pos, SEEK_SET) != 0
- || bfd_bwrite (finfo->outsyms, amt, output_bfd) != amt)
+ || bfd_bwrite (flinfo->outsyms, amt, output_bfd) != amt)
return FALSE;
BFD_ASSERT ((obj_raw_syment_count (output_bfd)
- + (outsym - finfo->outsyms) / osymesz)
+ + (outsym - flinfo->outsyms) / osymesz)
== output_index);
obj_raw_syment_count (output_bfd) = output_index;
else
{
bfd_size_type sz = o->rawsize ? o->rawsize : o->size;
- if (!bfd_get_section_contents (input_bfd, o, finfo->contents, 0, sz))
+ if (!bfd_get_section_contents (input_bfd, o, flinfo->contents, 0, sz))
return FALSE;
- contents = finfo->contents;
+ contents = flinfo->contents;
}
if ((o->flags & SEC_RELOC) != 0)
/* Read in the relocs. */
target_index = o->output_section->target_index;
internal_relocs = (xcoff_read_internal_relocs
- (input_bfd, o, FALSE, finfo->external_relocs,
+ (input_bfd, o, FALSE, flinfo->external_relocs,
TRUE,
- (finfo->section_info[target_index].relocs
+ (flinfo->section_info[target_index].relocs
+ o->output_section->reloc_count)));
if (internal_relocs == NULL)
return FALSE;
/* Call processor specific code to relocate the section
contents. */
- if (! bfd_coff_relocate_section (output_bfd, finfo->info,
+ if (! bfd_coff_relocate_section (output_bfd, flinfo->info,
input_bfd, o,
contents,
internal_relocs,
- finfo->internal_syms,
+ flinfo->internal_syms,
xcoff_data (input_bfd)->csects))
return FALSE;
offset = o->output_section->vma + o->output_offset - o->vma;
irel = internal_relocs;
irelend = irel + o->reloc_count;
- rel_hash = (finfo->section_info[target_index].rel_hashes
+ rel_hash = (flinfo->section_info[target_index].rel_hashes
+ o->output_section->reloc_count);
for (; irel < irelend; irel++, rel_hash++)
{
struct xcoff_link_hash_entry *h = NULL;
- struct internal_ldrel ldrel;
*rel_hash = NULL;
else
h = obj_xcoff_sym_hashes (input_bfd)[r_symndx];
- if (r_symndx != -1 && finfo->info->strip != strip_all)
+ if (r_symndx != -1 && flinfo->info->strip != strip_all)
{
if (h != NULL
&& h->smclas != XMC_TD
bfd_size_type amt;
amt = sizeof (* n);
- n = bfd_alloc (finfo->output_bfd, amt);
+ n = bfd_alloc (flinfo->output_bfd, amt);
if (n == NULL)
return FALSE;
- si = finfo->section_info + target_index;
+ si = flinfo->section_info + target_index;
n->next = si->toc_rel_hashes;
n->h = h;
n->rel = irel;
{
long indx;
- indx = finfo->sym_indices[r_symndx];
+ indx = flinfo->sym_indices[r_symndx];
if (indx == -1)
{
/* Relocations against a TC0 TOC anchor are
automatically transformed to be against
the TOC anchor in the output file. */
- is = finfo->internal_syms + r_symndx;
+ is = flinfo->internal_syms + r_symndx;
if (is->n_sclass == C_HIDEXT
&& is->n_numaux > 0)
{
(void *) &aux);
if (SMTYP_SMTYP (aux.x_csect.x_smtyp) == XTY_SD
&& aux.x_csect.x_smclas == XMC_TC0)
- indx = finfo->toc_symindx;
+ indx = flinfo->toc_symindx;
}
}
/* This reloc is against a symbol we are
stripping. It would be possible to handle
this case, but I don't think it's worth it. */
- is = finfo->internal_syms + r_symndx;
+ is = flinfo->internal_syms + r_symndx;
name = (_bfd_coff_internal_syment_name
(input_bfd, is, buf));
if (name == NULL)
return FALSE;
- if (! ((*finfo->info->callbacks->unattached_reloc)
- (finfo->info, name, input_bfd, o,
+ if (! ((*flinfo->info->callbacks->unattached_reloc)
+ (flinfo->info, name, input_bfd, o,
irel->r_vaddr)))
return FALSE;
}
}
}
- switch (irel->r_type)
+ if (xcoff_need_ldrel_p (flinfo->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:
- if (h != NULL
- && (h->root.type == bfd_link_hash_defined
- || h->root.type == bfd_link_hash_defweak)
- && bfd_is_abs_section (h->root.u.def.section))
- break;
- /* This reloc needs to be copied into the .loader
- section. */
- ldrel.l_vaddr = irel->r_vaddr;
- 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 (h->ldindx < 0)
- {
- (*_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)
- {
- (*_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, flinfo,
+ o->output_section, input_bfd,
+ irel, sec, h))
+ return FALSE;
}
}
obj_coff_keep_syms (input_bfd) = keep_syms;
- if (! finfo->info->keep_memory)
+ if (! flinfo->info->keep_memory)
{
if (! _bfd_coff_free_symbols (input_bfd))
return FALSE;
symbol. */
static bfd_boolean
-xcoff_find_tc0 (bfd *output_bfd, struct xcoff_final_link_info *finfo)
+xcoff_find_tc0 (bfd *output_bfd, struct xcoff_final_link_info *flinfo)
{
bfd_vma toc_start, toc_end, start, end, best_address;
asection *sec;
toc_start = ~(bfd_vma) 0;
toc_end = 0;
section_index = -1;
- for (input_bfd = finfo->info->input_bfds;
+ for (input_bfd = flinfo->info->input_bfds;
input_bfd != NULL;
input_bfd = input_bfd->link_next)
for (sec = input_bfd->sections; sec != NULL; sec = sec->next)
{
/* Find the lowest TOC csect that is still within range of TOC_END. */
best_address = toc_end;
- for (input_bfd = finfo->info->input_bfds;
+ for (input_bfd = flinfo->info->input_bfds;
input_bfd != NULL;
input_bfd = input_bfd->link_next)
for (sec = input_bfd->sections; sec != NULL; sec = sec->next)
}
/* Record the chosen TOC value. */
- finfo->toc_symindx = obj_raw_syment_count (output_bfd);
+ flinfo->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"))
+ if (!bfd_xcoff_put_symbol_name (output_bfd, flinfo->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);
+ bfd_coff_swap_sym_out (output_bfd, &irsym, flinfo->outsyms);
/* Fill out the auxillary csect information. */
memset (&iraux, 0, sizeof iraux);
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));
+ flinfo->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)
+ || bfd_bwrite (flinfo->outsyms, size, output_bfd) != size)
return FALSE;
obj_raw_syment_count (output_bfd) += 2;
static bfd_boolean
xcoff_write_global_symbol (struct xcoff_link_hash_entry *h, void * inf)
{
- struct xcoff_final_link_info *finfo = (struct xcoff_final_link_info *) inf;
+ struct xcoff_final_link_info *flinfo = (struct xcoff_final_link_info *) inf;
bfd *output_bfd;
bfd_byte *outsym;
struct internal_syment isym;
file_ptr pos;
bfd_size_type amt;
- output_bfd = finfo->output_bfd;
- outsym = finfo->outsyms;
+ output_bfd = flinfo->output_bfd;
+ outsym = flinfo->outsyms;
if (h->root.type == bfd_link_hash_warning)
{
}
/* If this symbol was garbage collected, just skip it. */
- if (xcoff_hash_table (finfo->info)->gc
+ if (xcoff_hash_table (flinfo->info)->gc
&& (h->flags & XCOFF_MARK) == 0)
return TRUE;
BFD_ASSERT (h->ldindx >= 0);
bfd_xcoff_swap_ldsym_out (output_bfd, ldsym,
- (finfo->ldsym +
+ (flinfo->ldsym +
(h->ldindx - 3)
- * bfd_xcoff_ldsymsz(finfo->output_bfd)));
+ * bfd_xcoff_ldsymsz(flinfo->output_bfd)));
h->ldsym = NULL;
}
/* If this symbol needs global linkage code, write it out. */
if (h->root.type == bfd_link_hash_defined
&& (h->root.u.def.section
- == xcoff_hash_table (finfo->info)->linkage_section))
+ == xcoff_hash_table (flinfo->info)->linkage_section))
{
bfd_byte *p;
bfd_vma tocoff;
asection *osec;
int oindx;
struct internal_reloc *irel;
- struct internal_ldrel ldrel;
struct internal_syment irsym;
union internal_auxent iraux;
tocsec = h->toc_section;
osec = tocsec->output_section;
oindx = osec->target_index;
- irel = finfo->section_info[oindx].relocs + osec->reloc_count;
+ irel = flinfo->section_info[oindx].relocs + osec->reloc_count;
irel->r_vaddr = (osec->vma
+ tocsec->output_offset
+ h->u.toc_offset);
return FALSE;
irel->r_type = R_POS;
- finfo->section_info[oindx].rel_hashes[osec->reloc_count] = NULL;
+ flinfo->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, flinfo, osec,
+ output_bfd, irel, NULL, h))
+ return FALSE;
/* We need to emit a symbol to define a csect which holds
the reloc. */
- if (finfo->info->strip != strip_all)
+ if (flinfo->info->strip != strip_all)
{
- result = bfd_xcoff_put_symbol_name (output_bfd, finfo->strtab,
+ result = bfd_xcoff_put_symbol_name (output_bfd, flinfo->strtab,
&irsym, h->root.root.string);
if (!result)
return FALSE;
pos = obj_sym_filepos (output_bfd);
pos += (obj_raw_syment_count (output_bfd)
* bfd_coff_symesz (output_bfd));
- amt = outsym - finfo->outsyms;
+ amt = outsym - flinfo->outsyms;
if (bfd_seek (output_bfd, pos, SEEK_SET) != 0
- || bfd_bwrite (finfo->outsyms, amt, output_bfd) != amt)
+ || bfd_bwrite (flinfo->outsyms, amt, output_bfd) != amt)
return FALSE;
obj_raw_syment_count (output_bfd) +=
- (outsym - finfo->outsyms) / bfd_coff_symesz (output_bfd);
+ (outsym - flinfo->outsyms) / bfd_coff_symesz (output_bfd);
- outsym = finfo->outsyms;
+ outsym = flinfo->outsyms;
}
}
}
if ((h->flags & XCOFF_DESCRIPTOR) != 0
&& h->root.type == bfd_link_hash_defined
&& (h->root.u.def.section
- == xcoff_hash_table (finfo->info)->descriptor_section))
+ == xcoff_hash_table (flinfo->info)->descriptor_section))
{
asection *sec;
asection *osec;
struct xcoff_link_hash_entry *hentry;
asection *esec;
struct internal_reloc *irel;
- struct internal_ldrel ldrel;
asection *tsec;
unsigned int reloc_size, byte_size;
|| hentry->root.type == bfd_link_hash_defweak));
esec = hentry->root.u.def.section;
- irel = finfo->section_info[oindx].relocs + osec->reloc_count;
+ irel = flinfo->section_info[oindx].relocs + osec->reloc_count;
irel->r_vaddr = (osec->vma
+ sec->output_offset
+ h->root.u.def.value);
irel->r_symndx = esec->output_section->target_index;
irel->r_type = R_POS;
irel->r_size = reloc_size;
- finfo->section_info[oindx].rel_hashes[osec->reloc_count] = NULL;
+ flinfo->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, flinfo, osec,
+ output_bfd, irel, esec, NULL))
+ return FALSE;
/* There are three items to write out,
the address of the code
irel->r_symndx = tsec->output_section->target_index;
irel->r_type = R_POS;
irel->r_size = reloc_size;
- finfo->section_info[oindx].rel_hashes[osec->reloc_count] = NULL;
+ flinfo->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, flinfo, osec,
+ output_bfd, irel, tsec, NULL))
+ return FALSE;
}
- if (h->indx >= 0 || finfo->info->strip == strip_all)
+ if (h->indx >= 0 || flinfo->info->strip == strip_all)
{
- BFD_ASSERT (outsym == finfo->outsyms);
+ BFD_ASSERT (outsym == flinfo->outsyms);
return TRUE;
}
if (h->indx != -2
- && (finfo->info->strip == strip_all
- || (finfo->info->strip == strip_some
- && bfd_hash_lookup (finfo->info->keep_hash, h->root.root.string,
+ && (flinfo->info->strip == strip_all
+ || (flinfo->info->strip == strip_some
+ && bfd_hash_lookup (flinfo->info->keep_hash, h->root.root.string,
FALSE, FALSE) == NULL)))
{
- BFD_ASSERT (outsym == finfo->outsyms);
+ BFD_ASSERT (outsym == flinfo->outsyms);
return TRUE;
}
if (h->indx != -2
&& (h->flags & (XCOFF_REF_REGULAR | XCOFF_DEF_REGULAR)) == 0)
{
- BFD_ASSERT (outsym == finfo->outsyms);
+ BFD_ASSERT (outsym == flinfo->outsyms);
return TRUE;
}
h->indx = obj_raw_syment_count (output_bfd);
- result = bfd_xcoff_put_symbol_name (output_bfd, finfo->strtab, &isym,
+ result = bfd_xcoff_put_symbol_name (output_bfd, flinfo->strtab, &isym,
h->root.root.string);
if (!result)
return FALSE;
{
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
if ((h->flags & XCOFF_HAS_SIZE) != 0)
{
- for (l = xcoff_hash_table (finfo->info)->size_list;
+ for (l = xcoff_hash_table (flinfo->info)->size_list;
l != NULL;
l = l->next)
{
/* 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);
pos = obj_sym_filepos (output_bfd);
pos += obj_raw_syment_count (output_bfd) * bfd_coff_symesz (output_bfd);
- amt = outsym - finfo->outsyms;
+ amt = outsym - flinfo->outsyms;
if (bfd_seek (output_bfd, pos, SEEK_SET) != 0
- || bfd_bwrite (finfo->outsyms, amt, output_bfd) != amt)
+ || bfd_bwrite (flinfo->outsyms, amt, output_bfd) != amt)
return FALSE;
obj_raw_syment_count (output_bfd) +=
- (outsym - finfo->outsyms) / bfd_coff_symesz (output_bfd);
+ (outsym - flinfo->outsyms) / bfd_coff_symesz (output_bfd);
return TRUE;
}
static bfd_boolean
xcoff_reloc_link_order (bfd *output_bfd,
- struct xcoff_final_link_info *finfo,
+ struct xcoff_final_link_info *flinfo,
asection *output_section,
struct bfd_link_order *link_order)
{
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
}
h = ((struct xcoff_link_hash_entry *)
- bfd_wrapped_link_hash_lookup (output_bfd, finfo->info,
+ bfd_wrapped_link_hash_lookup (output_bfd, flinfo->info,
link_order->u.reloc.p->u.name,
FALSE, FALSE, TRUE));
if (h == NULL)
{
- if (! ((*finfo->info->callbacks->unattached_reloc)
- (finfo->info, link_order->u.reloc.p->u.name, NULL, NULL, (bfd_vma) 0)))
+ if (! ((*flinfo->info->callbacks->unattached_reloc)
+ (flinfo->info, link_order->u.reloc.p->u.name, NULL, NULL, (bfd_vma) 0)))
return FALSE;
return TRUE;
}
- if (h->root.type == bfd_link_hash_common)
- {
- hsec = h->root.u.c.p->section;
- hval = 0;
- }
- else if (h->root.type == bfd_link_hash_defined
- || h->root.type == bfd_link_hash_defweak)
- {
- hsec = h->root.u.def.section;
- hval = h->root.u.def.value;
- }
+ 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)
case bfd_reloc_outofrange:
abort ();
case bfd_reloc_overflow:
- if (! ((*finfo->info->callbacks->reloc_overflow)
- (finfo->info, NULL, link_order->u.reloc.p->u.name,
+ if (! ((*flinfo->info->callbacks->reloc_overflow)
+ (flinfo->info, NULL, link_order->u.reloc.p->u.name,
howto->name, addend, NULL, NULL, (bfd_vma) 0)))
{
free (buf);
/* Store the reloc information in the right place. It will get
swapped and written out at the end of the final_link routine. */
- irel = (finfo->section_info[output_section->target_index].relocs
+ irel = (flinfo->section_info[output_section->target_index].relocs
+ output_section->reloc_count);
- rel_hash_ptr = (finfo->section_info[output_section->target_index].rel_hashes
+ rel_hash_ptr = (flinfo->section_info[output_section->target_index].rel_hashes
+ output_section->reloc_count);
memset (irel, 0, sizeof (struct internal_reloc));
++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 (flinfo->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, flinfo, 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;
}
_bfd_xcoff_bfd_final_link (bfd *abfd, struct bfd_link_info *info)
{
bfd_size_type symesz;
- struct xcoff_final_link_info finfo;
+ struct xcoff_final_link_info flinfo;
asection *o;
struct bfd_link_order *p;
bfd_size_type max_contents_size;
symesz = bfd_coff_symesz (abfd);
- finfo.info = info;
- finfo.output_bfd = abfd;
- finfo.strtab = NULL;
- finfo.section_info = NULL;
- finfo.last_file_index = -1;
- finfo.toc_symindx = -1;
- finfo.internal_syms = NULL;
- finfo.sym_indices = NULL;
- finfo.outsyms = NULL;
- finfo.linenos = NULL;
- 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)));
+ flinfo.info = info;
+ flinfo.output_bfd = abfd;
+ flinfo.strtab = NULL;
+ flinfo.section_info = NULL;
+ flinfo.last_file_index = -1;
+ flinfo.toc_symindx = -1;
+ flinfo.internal_syms = NULL;
+ flinfo.sym_indices = NULL;
+ flinfo.outsyms = NULL;
+ flinfo.linenos = NULL;
+ flinfo.contents = NULL;
+ flinfo.external_relocs = NULL;
+
+ if (xcoff_hash_table (info)->loader_section)
+ {
+ flinfo.ldsym = (xcoff_hash_table (info)->loader_section->contents
+ + bfd_xcoff_ldhdrsz (abfd));
+ flinfo.ldrel = (xcoff_hash_table (info)->loader_section->contents
+ + bfd_xcoff_ldhdrsz (abfd)
+ + (xcoff_hash_table (info)->ldhdr.l_nsyms
+ * bfd_xcoff_ldsymsz (abfd)));
+ }
+ else
+ {
+ flinfo.ldsym = NULL;
+ flinfo.ldrel = NULL;
+ }
xcoff_data (abfd)->coff.link_info = info;
- finfo.strtab = _bfd_stringtab_init ();
- if (finfo.strtab == NULL)
+ flinfo.strtab = _bfd_stringtab_init ();
+ if (flinfo.strtab == NULL)
goto error_return;
/* Count the relocation entries required for the output file.
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->flags & SEC_IN_MEMORY) == 0)
+ {
+ if (sec->rawsize > max_contents_size)
+ max_contents_size = sec->rawsize;
+ if (sec->size > max_contents_size)
+ max_contents_size = sec->size;
+ }
if (coff_section_data (sec->owner, sec) != NULL
&& xcoff_section_data (sec->owner, sec) != NULL
&& (xcoff_section_data (sec->owner, sec)->lineno_count
the target_index fields are 1 based. */
amt = abfd->section_count + 1;
amt *= sizeof (struct xcoff_link_section_info);
- finfo.section_info = bfd_malloc (amt);
- if (finfo.section_info == NULL)
+ flinfo.section_info = bfd_malloc (amt);
+ if (flinfo.section_info == NULL)
goto error_return;
for (i = 0; i <= abfd->section_count; i++)
{
- finfo.section_info[i].relocs = NULL;
- finfo.section_info[i].rel_hashes = NULL;
- finfo.section_info[i].toc_rel_hashes = NULL;
+ flinfo.section_info[i].relocs = NULL;
+ flinfo.section_info[i].rel_hashes = NULL;
+ flinfo.section_info[i].toc_rel_hashes = NULL;
}
}
would be slow. */
amt = o->reloc_count;
amt *= sizeof (struct internal_reloc);
- finfo.section_info[o->target_index].relocs = bfd_malloc (amt);
+ flinfo.section_info[o->target_index].relocs = bfd_malloc (amt);
amt = o->reloc_count;
amt *= sizeof (struct xcoff_link_hash_entry *);
- finfo.section_info[o->target_index].rel_hashes = bfd_malloc (amt);
+ flinfo.section_info[o->target_index].rel_hashes = bfd_malloc (amt);
- if (finfo.section_info[o->target_index].relocs == NULL
- || finfo.section_info[o->target_index].rel_hashes == NULL)
+ if (flinfo.section_info[o->target_index].relocs == NULL
+ || flinfo.section_info[o->target_index].rel_hashes == NULL)
goto error_return;
if (o->reloc_count > max_output_reloc_count)
/* We now know the size of the relocs, so we can determine the file
positions of the line numbers. */
line_filepos = rel_filepos;
- finfo.line_filepos = line_filepos;
+ flinfo.line_filepos = line_filepos;
linesz = bfd_coff_linesz (abfd);
for (o = abfd->sections; o != NULL; o = o->next)
{
/* Allocate some buffers used while linking. */
amt = max_sym_count * sizeof (struct internal_syment);
- finfo.internal_syms = bfd_malloc (amt);
+ flinfo.internal_syms = bfd_malloc (amt);
amt = max_sym_count * sizeof (long);
- finfo.sym_indices = bfd_malloc (amt);
+ flinfo.sym_indices = bfd_malloc (amt);
amt = (max_sym_count + 1) * symesz;
- finfo.outsyms = bfd_malloc (amt);
+ flinfo.outsyms = bfd_malloc (amt);
amt = max_lineno_count * bfd_coff_linesz (abfd);
- finfo.linenos = bfd_malloc (amt);
+ flinfo.linenos = bfd_malloc (amt);
amt = max_contents_size;
- finfo.contents = bfd_malloc (amt);
+ flinfo.contents = bfd_malloc (amt);
amt = max_reloc_count * relsz;
- finfo.external_relocs = bfd_malloc (amt);
-
- if ((finfo.internal_syms == NULL && max_sym_count > 0)
- || (finfo.sym_indices == NULL && max_sym_count > 0)
- || finfo.outsyms == NULL
- || (finfo.linenos == NULL && max_lineno_count > 0)
- || (finfo.contents == NULL && max_contents_size > 0)
- || (finfo.external_relocs == NULL && max_reloc_count > 0))
+ flinfo.external_relocs = bfd_malloc (amt);
+
+ if ((flinfo.internal_syms == NULL && max_sym_count > 0)
+ || (flinfo.sym_indices == NULL && max_sym_count > 0)
+ || flinfo.outsyms == NULL
+ || (flinfo.linenos == NULL && max_lineno_count > 0)
+ || (flinfo.contents == NULL && max_contents_size > 0)
+ || (flinfo.external_relocs == NULL && max_reloc_count > 0))
goto error_return;
obj_raw_syment_count (abfd) = 0;
/* Find a TOC symbol, if we need one. */
- if (!xcoff_find_tc0 (abfd, &finfo))
+ if (!xcoff_find_tc0 (abfd, &flinfo))
goto error_return;
/* We now know the position of everything in the file, except that
sub = p->u.indirect.section->owner;
if (! sub->output_has_begun)
{
- if (! xcoff_link_input_bfd (&finfo, sub))
+ if (! xcoff_link_input_bfd (&flinfo, sub))
goto error_return;
sub->output_has_begun = TRUE;
}
else if (p->type == bfd_section_reloc_link_order
|| p->type == bfd_symbol_reloc_link_order)
{
- if (! xcoff_reloc_link_order (abfd, &finfo, o, p))
+ if (! xcoff_reloc_link_order (abfd, &flinfo, o, p))
goto error_return;
}
else
}
/* Free up the buffers used by xcoff_link_input_bfd. */
- if (finfo.internal_syms != NULL)
+ if (flinfo.internal_syms != NULL)
{
- free (finfo.internal_syms);
- finfo.internal_syms = NULL;
+ free (flinfo.internal_syms);
+ flinfo.internal_syms = NULL;
}
- if (finfo.sym_indices != NULL)
+ if (flinfo.sym_indices != NULL)
{
- free (finfo.sym_indices);
- finfo.sym_indices = NULL;
+ free (flinfo.sym_indices);
+ flinfo.sym_indices = NULL;
}
- if (finfo.linenos != NULL)
+ if (flinfo.linenos != NULL)
{
- free (finfo.linenos);
- finfo.linenos = NULL;
+ free (flinfo.linenos);
+ flinfo.linenos = NULL;
}
- if (finfo.contents != NULL)
+ if (flinfo.contents != NULL)
{
- free (finfo.contents);
- finfo.contents = NULL;
+ free (flinfo.contents);
+ flinfo.contents = NULL;
}
- if (finfo.external_relocs != NULL)
+ if (flinfo.external_relocs != NULL)
{
- free (finfo.external_relocs);
- finfo.external_relocs = NULL;
+ free (flinfo.external_relocs);
+ flinfo.external_relocs = NULL;
}
/* The value of the last C_FILE symbol is supposed to be -1. Write
it out again. */
- if (finfo.last_file_index != -1)
+ if (flinfo.last_file_index != -1)
{
- finfo.last_file.n_value = -(bfd_vma) 1;
- bfd_coff_swap_sym_out (abfd, (void *) &finfo.last_file,
- (void *) finfo.outsyms);
- pos = obj_sym_filepos (abfd) + finfo.last_file_index * symesz;
+ flinfo.last_file.n_value = -(bfd_vma) 1;
+ bfd_coff_swap_sym_out (abfd, (void *) &flinfo.last_file,
+ (void *) flinfo.outsyms);
+ pos = obj_sym_filepos (abfd) + flinfo.last_file_index * symesz;
if (bfd_seek (abfd, pos, SEEK_SET) != 0
- || bfd_bwrite (finfo.outsyms, symesz, abfd) != symesz)
+ || bfd_bwrite (flinfo.outsyms, symesz, abfd) != symesz)
goto error_return;
}
input files. */
xcoff_link_hash_traverse (xcoff_hash_table (info),
xcoff_write_global_symbol,
- (void *) &finfo);
+ (void *) &flinfo);
- if (finfo.outsyms != NULL)
+ if (flinfo.outsyms != NULL)
{
- free (finfo.outsyms);
- finfo.outsyms = NULL;
+ free (flinfo.outsyms);
+ flinfo.outsyms = NULL;
}
/* Now that we have written out all the global symbols, we know the
if (o->reloc_count == 0)
continue;
- irel = finfo.section_info[o->target_index].relocs;
+ irel = flinfo.section_info[o->target_index].relocs;
irelend = irel + o->reloc_count;
- rel_hash = finfo.section_info[o->target_index].rel_hashes;
+ rel_hash = flinfo.section_info[o->target_index].rel_hashes;
for (; irel < irelend; irel++, rel_hash++, erel += relsz)
{
if (*rel_hash != NULL)
}
}
- for (toc_rel_hash = finfo.section_info[o->target_index].toc_rel_hashes;
+ for (toc_rel_hash = flinfo.section_info[o->target_index].toc_rel_hashes;
toc_rel_hash != NULL;
toc_rel_hash = toc_rel_hash->next)
{
appear in the symbol table, which is not necessarily by
address. So we sort them here. There may be a better way to
do this. */
- qsort ((void *) finfo.section_info[o->target_index].relocs,
+ qsort ((void *) flinfo.section_info[o->target_index].relocs,
o->reloc_count, sizeof (struct internal_reloc),
xcoff_sort_relocs);
- irel = finfo.section_info[o->target_index].relocs;
+ irel = flinfo.section_info[o->target_index].relocs;
irelend = irel + o->reloc_count;
erel = external_relocs;
for (; irel < irelend; irel++, rel_hash++, erel += relsz)
}
/* Free up the section information. */
- if (finfo.section_info != NULL)
+ if (flinfo.section_info != NULL)
{
unsigned int i;
for (i = 0; i < abfd->section_count; i++)
{
- if (finfo.section_info[i].relocs != NULL)
- free (finfo.section_info[i].relocs);
- if (finfo.section_info[i].rel_hashes != NULL)
- free (finfo.section_info[i].rel_hashes);
+ if (flinfo.section_info[i].relocs != NULL)
+ free (flinfo.section_info[i].relocs);
+ if (flinfo.section_info[i].rel_hashes != NULL)
+ free (flinfo.section_info[i].rel_hashes);
}
- free (finfo.section_info);
- finfo.section_info = NULL;
+ free (flinfo.section_info);
+ flinfo.section_info = NULL;
}
/* 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 *) flinfo.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;
if (bfd_seek (abfd, pos, SEEK_SET) != 0)
goto error_return;
H_PUT_32 (abfd,
- _bfd_stringtab_size (finfo.strtab) + STRING_SIZE_SIZE,
+ _bfd_stringtab_size (flinfo.strtab) + STRING_SIZE_SIZE,
strbuf);
amt = STRING_SIZE_SIZE;
if (bfd_bwrite (strbuf, amt, abfd) != amt)
goto error_return;
- if (! _bfd_stringtab_emit (abfd, finfo.strtab))
+ if (! _bfd_stringtab_emit (abfd, flinfo.strtab))
goto error_return;
- _bfd_stringtab_free (finfo.strtab);
+ _bfd_stringtab_free (flinfo.strtab);
/* Write out the debugging string table. */
o = xcoff_hash_table (info)->debug_section;
return TRUE;
error_return:
- if (finfo.strtab != NULL)
- _bfd_stringtab_free (finfo.strtab);
+ if (flinfo.strtab != NULL)
+ _bfd_stringtab_free (flinfo.strtab);
- if (finfo.section_info != NULL)
+ if (flinfo.section_info != NULL)
{
unsigned int i;
for (i = 0; i < abfd->section_count; i++)
{
- if (finfo.section_info[i].relocs != NULL)
- free (finfo.section_info[i].relocs);
- if (finfo.section_info[i].rel_hashes != NULL)
- free (finfo.section_info[i].rel_hashes);
+ if (flinfo.section_info[i].relocs != NULL)
+ free (flinfo.section_info[i].relocs);
+ if (flinfo.section_info[i].rel_hashes != NULL)
+ free (flinfo.section_info[i].rel_hashes);
}
- free (finfo.section_info);
- }
-
- if (finfo.internal_syms != NULL)
- free (finfo.internal_syms);
- if (finfo.sym_indices != NULL)
- free (finfo.sym_indices);
- if (finfo.outsyms != NULL)
- free (finfo.outsyms);
- if (finfo.linenos != NULL)
- free (finfo.linenos);
- if (finfo.contents != NULL)
- free (finfo.contents);
- if (finfo.external_relocs != NULL)
- free (finfo.external_relocs);
+ free (flinfo.section_info);
+ }
+
+ if (flinfo.internal_syms != NULL)
+ free (flinfo.internal_syms);
+ if (flinfo.sym_indices != NULL)
+ free (flinfo.sym_indices);
+ if (flinfo.outsyms != NULL)
+ free (flinfo.outsyms);
+ if (flinfo.linenos != NULL)
+ free (flinfo.linenos);
+ if (flinfo.contents != NULL)
+ free (flinfo.contents);
+ if (flinfo.external_relocs != NULL)
+ free (flinfo.external_relocs);
if (external_relocs != NULL)
free (external_relocs);
return FALSE;