/* 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
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 (strcmp ((*pp)->path, imppath) == 0
+ && strcmp ((*pp)->file, impfile) == 0
+ && strcmp ((*pp)->member, impmember) == 0)
+ break;
+ }
+
+ if (*pp == NULL)
+ {
+ struct xcoff_import_file *n;
+ bfd_size_type amt = sizeof (* n);
+
+ n = bfd_alloc (info->output_bfd, amt);
+ if (n == NULL)
+ return FALSE;
+ n->next = NULL;
+ n->path = imppath;
+ n->file = impfile;
+ n->member = impmember;
+ *pp = n;
+ }
+ h->ldindx = c;
+ }
+ return TRUE;
+}
+\f
/* H is the bfd symbol associated with exported .loader symbol LDSYM.
Return true if LDSYM defines H. */
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;
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;
|| 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)->flags & XCOFF_DEF_REGULAR) == 0
- && ((*sym_hash)->flags & XCOFF_DEF_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. */
{
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;
}
}
\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. */
-
-static bfd_boolean
-xcoff_set_import_path (struct bfd_link_info *info,
- struct xcoff_link_hash_entry *h,
- const char *imppath, const char *impfile,
- const char *impmember)
-{
- unsigned int c;
- struct xcoff_import_file **pp;
-
- /* We overload the ldindx field to hold the l_ifile value for this
- symbol. */
- BFD_ASSERT (h->ldsym == NULL);
- BFD_ASSERT ((h->flags & XCOFF_BUILT_LDSYM) == 0);
- if (imppath == NULL)
- h->ldindx = -1;
- else
- {
- /* We start c at 1 because the first entry in the import list is
- reserved for the library search path. */
- for (pp = &xcoff_hash_table (info)->imports, c = 1;
- *pp != NULL;
- pp = &(*pp)->next, ++c)
- {
- if (strcmp ((*pp)->path, imppath) == 0
- && strcmp ((*pp)->file, impfile) == 0
- && strcmp ((*pp)->member, impmember) == 0)
- break;
- }
-
- if (*pp == NULL)
- {
- struct xcoff_import_file *n;
- bfd_size_type amt = sizeof (* n);
-
- n = bfd_alloc (info->output_bfd, amt);
- if (n == NULL)
- return FALSE;
- n->next = NULL;
- n->path = imppath;
- n->file = impfile;
- n->member = impmember;
- *pp = n;
- }
- h->ldindx = c;
- }
- return TRUE;
-}
\f
/* Return true if the given bfd contains at least one shared object. */
static bfd_boolean
-xcoff_archive_contains_shared_object_p (bfd *archive)
+xcoff_archive_contains_shared_object_p (struct bfd_link_info *info,
+ bfd *archive)
{
+ struct xcoff_archive_info *archive_info;
bfd *member;
- member = bfd_openr_next_archived_file (archive, NULL);
- while (member != NULL && (member->flags & DYNAMIC) == 0)
- member = bfd_openr_next_archived_file (archive, member);
- return member != NULL;
+ archive_info = xcoff_get_archive_info (info, archive);
+ if (!archive_info->know_contains_shared_object_p)
+ {
+ member = bfd_openr_next_archived_file (archive, NULL);
+ while (member != NULL && (member->flags & DYNAMIC) == 0)
+ member = bfd_openr_next_archived_file (archive, member);
+
+ archive_info->contains_shared_object_p = (member != NULL);
+ archive_info->know_contains_shared_object_p = 1;
+ }
+ return archive_info->contains_shared_object_p;
}
/* Symbol H qualifies for export by -bexpfull. Return true if it also
specified by AUTO_EXPORT_FLAGS. */
static bfd_boolean
-xcoff_auto_export_p (struct xcoff_link_hash_entry *h,
+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. */
owner = h->root.u.def.section->owner;
if (owner != NULL
&& owner->my_archive != NULL
- && xcoff_archive_contains_shared_object_p (owner->my_archive))
+ && xcoff_archive_contains_shared_object_p (info, owner->my_archive))
return FALSE;
}
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. */
/* 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
/* 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))
struct xcoff_loader_info *ldinfo;
ldinfo = (struct xcoff_loader_info *) data;
- if (xcoff_auto_export_p (h, ldinfo->auto_export_flags))
+ if (xcoff_auto_export_p (ldinfo->info, h, ldinfo->auto_export_flags))
{
if (!xcoff_mark_symbol (ldinfo->info, h))
ldinfo->failed = TRUE;
}
}
+/* 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 (xcoff_auto_export_p (h, ldinfo->auto_export_flags))
- h->flags |= XCOFF_EXPORT;
-
- /* We don't want to garbage collect symbols which are not defined in
- XCOFF files. This is a convenient place to mark them. */
- 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. */
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 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.
asection **special_sections,
bfd_boolean rtld)
{
- asection *lsec;
struct xcoff_loader_info ldinfo;
int i;
- size_t impsize, impcount;
- struct xcoff_import_file *fl;
- struct internal_ldhdr *ldhdr;
- bfd_size_type stoff;
- char *out;
asection *sec;
bfd *sub;
struct bfd_strtab_hash *debug_strtab;
xcoff_hash_table (info)->rtld = rtld;
/* __rtinit */
- if (info->init_function || info->fini_function || rtld)
+ if (xcoff_hash_table (info)->loader_section
+ && (info->init_function || info->fini_function || rtld))
{
struct xcoff_link_hash_entry *hsym;
struct internal_ldsym *ldsym;
/* 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)
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)
{
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. */
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;
{
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
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);
+ 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;
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)
{
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;