/* POWER/PowerPC XCOFF linker support.
- Copyright (C) 1995-2014 Free Software Foundation, Inc.
+ Copyright (C) 1995-2020 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 "libcoff.h"
#include "libxcoff.h"
#include "libiberty.h"
+#include "xcofflink.h"
/* This file holds the XCOFF linker code. */
/* Destroy an XCOFF link hash table. */
-void
-_bfd_xcoff_bfd_link_hash_table_free (struct bfd_link_hash_table *hash)
+static void
+_bfd_xcoff_bfd_link_hash_table_free (bfd *obfd)
{
- struct xcoff_link_hash_table *ret = (struct xcoff_link_hash_table *) hash;
+ struct xcoff_link_hash_table *ret;
- _bfd_stringtab_free (ret->debug_strtab);
- bfd_hash_table_free (&ret->root.table);
- free (ret);
+ ret = (struct xcoff_link_hash_table *) obfd->link.hash;
+ if (ret->archive_info)
+ htab_delete (ret->archive_info);
+ if (ret->debug_strtab)
+ _bfd_stringtab_free (ret->debug_strtab);
+ _bfd_generic_link_hash_table_free (obfd);
}
/* Create an XCOFF link hash table. */
ret->debug_strtab = _bfd_xcoff_stringtab_init ();
ret->archive_info = htab_create (37, xcoff_archive_info_hash,
xcoff_archive_info_eq, NULL);
+ if (!ret->debug_strtab || !ret->archive_info)
+ {
+ _bfd_xcoff_bfd_link_hash_table_free (abfd);
+ return NULL;
+ }
+ ret->root.hash_table_free = _bfd_xcoff_bfd_link_hash_table_free;
/* The linker will always generate a full a.out header. We need to
record that fact now, before the sizeof_headers routine could be
output file. */
if (info->output_bfd->xvec != abfd->xvec)
{
- (*_bfd_error_handler)
- (_("%s: XCOFF shared object when not producing XCOFF output"),
- bfd_get_filename (abfd));
+ _bfd_error_handler
+ (_("%pB: XCOFF shared object when not producing XCOFF output"),
+ abfd);
bfd_set_error (bfd_error_invalid_operation);
return FALSE;
}
lsec = bfd_get_section_by_name (abfd, ".loader");
if (lsec == NULL)
{
- (*_bfd_error_handler)
- (_("%s: dynamic object with no .loader section"),
- bfd_get_filename (abfd));
+ _bfd_error_handler
+ (_("%pB: dynamic object with no .loader section"),
+ abfd);
bfd_set_error (bfd_error_no_symbols);
return FALSE;
}
return FALSE;
n->next = NULL;
- if (abfd->my_archive == NULL)
+ if (abfd->my_archive == NULL || bfd_is_thin_archive (abfd->my_archive))
{
if (!bfd_xcoff_split_import_path (abfd, abfd->filename,
&n->path, &n->file))
won't work if we're producing an XCOFF output file with no
XCOFF input files. FIXME. */
- if (!info->relocatable
+ if (!bfd_link_relocatable (info)
&& xcoff_hash_table (info)->loader_section == NULL)
{
asection *lsec;
if (csect != NULL)
*csect_cache = csect;
else if (first_csect == NULL
- || sym.n_sclass == C_FILE || sym.n_sclass == C_DWARF)
+ || sym.n_sclass == C_FILE || sym.n_sclass == C_DWARF)
*csect_cache = coff_section_from_bfd_index (abfd, sym.n_scnum);
else
*csect_cache = NULL;
enclosing = xcoff_section_data (abfd, csect)->enclosing;
if (enclosing == NULL)
{
- (*_bfd_error_handler)
- (_("%B: `%s' has line numbers but no enclosing section"),
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: `%s' has line numbers but no enclosing section"),
abfd, name);
bfd_set_error (bfd_error_bad_value);
goto error_return;
/* Pick up the csect auxiliary information. */
if (sym.n_numaux == 0)
{
- (*_bfd_error_handler)
- (_("%B: class %d symbol `%s' has no aux entries"),
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: class %d symbol `%s' has no aux entries"),
abfd, sym.n_sclass, name);
bfd_set_error (bfd_error_bad_value);
goto error_return;
switch (smtyp)
{
default:
- (*_bfd_error_handler)
- (_("%B: symbol `%s' has unrecognized csect type %d"),
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: symbol `%s' has unrecognized csect type %d"),
abfd, name, smtyp);
bfd_set_error (bfd_error_bad_value);
goto error_return;
|| sym.n_scnum != N_UNDEF
|| aux.x_csect.x_scnlen.l != 0)
{
- (*_bfd_error_handler)
- (_("%B: bad XTY_ER symbol `%s': class %d scnum %d scnlen %d"),
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: bad XTY_ER symbol `%s': class %d scnum %d "
+ "scnlen %" PRId64),
abfd, name, sym.n_sclass, sym.n_scnum,
- aux.x_csect.x_scnlen.l);
+ (int64_t) aux.x_csect.x_scnlen.l);
bfd_set_error (bfd_error_bad_value);
goto error_return;
}
if (sym.n_sclass != C_HIDEXT
|| aux.x_csect.x_scnlen.l != 0)
{
- (*_bfd_error_handler)
- (_("%B: XMC_TC0 symbol `%s' is class %d scnlen %d"),
- abfd, name, sym.n_sclass, aux.x_csect.x_scnlen.l);
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: XMC_TC0 symbol `%s' is class %d scnlen %" PRId64),
+ abfd, name, sym.n_sclass, (int64_t) aux.x_csect.x_scnlen.l);
bfd_set_error (bfd_error_bad_value);
goto error_return;
}
|| ((bfd_vma) sym.n_value + aux.x_csect.x_scnlen.l
> enclosing->vma + enclosing->size)))
{
- (*_bfd_error_handler)
- (_("%B: csect `%s' not in enclosing section"),
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: csect `%s' not in enclosing section"),
abfd, name);
bfd_set_error (bfd_error_bad_value);
goto error_return;
}
if (bad)
{
- (*_bfd_error_handler)
- (_("%B: misplaced XTY_LD `%s'"),
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: misplaced XTY_LD `%s'"),
abfd, name);
bfd_set_error (bfd_error_bad_value);
goto error_return;
}
- csect = section;
+ csect = section;
value = sym.n_value - csect->vma;
}
break;
if (EXTERN_SYM_P (sym.n_sclass))
{
- bfd_boolean copy;
+ bfd_boolean copy, ok;
flagword flags;
BFD_ASSERT (section != NULL);
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. */
- else 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),
sure the XCOFF linker is wholly prepared to
handle them, and that would only be a warning,
not an error. */
- if (! ((*info->callbacks->multiple_definition)
- (info, &(*sym_hash)->root, NULL, NULL, (bfd_vma) 0)))
- goto error_return;
+ (*info->callbacks->multiple_definition) (info,
+ &(*sym_hash)->root,
+ NULL, NULL,
+ (bfd_vma) 0);
/* Try not to give this error too many times. */
(*sym_hash)->flags &= ~XCOFF_MULTIPLY_DEFINED;
}
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,
- (struct bfd_link_hash_entry **) sym_hash)))
- goto error_return;
+ ok = (_bfd_generic_link_add_one_symbol
+ (info, abfd, name, flags, section, value, NULL, copy, TRUE,
+ (struct bfd_link_hash_entry **) sym_hash));
last_real->next = first_csect;
+ if (!ok)
+ goto error_return;
if (smtyp == XTY_CM)
{
= csect->alignment_power;
}
- if (info->output_bfd->xvec == abfd->xvec)
+ if (info->output_bfd->xvec == abfd->xvec)
{
int flag;
for (o = abfd->sections; o != first_csect; o = o->next)
{
/* Debugging sections have no csects. */
- if (bfd_get_section_flags (abfd, o) & SEC_DEBUGGING)
- continue;
+ if (bfd_section_flags (o) & SEC_DEBUGGING)
+ continue;
/* Reset the section size and the line number count, since the
data is now attached to the csects. Don't reset the size of
the .debug section, since we need to read it below in
bfd_xcoff_size_dynamic_sections. */
- if (strcmp (bfd_get_section_name (abfd, o), ".debug") != 0)
+ if (strcmp (bfd_section_name (o), ".debug") != 0)
o->size = 0;
o->lineno_count = 0;
{
if (*rel_csect == NULL)
{
- (*_bfd_error_handler)
- (_("%B: reloc %s:%d not in csect"),
- abfd, o->name, i);
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: reloc %s:%" PRId64 " not in csect"),
+ abfd, o->name, (int64_t) i);
bfd_set_error (bfd_error_bad_value);
goto error_return;
}
/* We identify all function symbols that are the target
of a relocation, so that we can create glue code for
functions imported from dynamic objects. */
- if (info->output_bfd->xvec == abfd->xvec
+ if (info->output_bfd->xvec == abfd->xvec
&& *rel_csect != bfd_und_section_ptr
&& obj_xcoff_sym_hashes (abfd)[rel->r_symndx] != NULL)
{
{
if (!(*info->callbacks
->add_archive_element) (info, abfd, name, subsbfd))
- return FALSE;
+ continue;
*pneeded = TRUE;
return TRUE;
}
undefined references in shared objects. */
if (h != NULL
&& h->type == bfd_link_hash_undefined
- && (info->output_bfd->xvec != abfd->xvec
+ && (info->output_bfd->xvec != abfd->xvec
|| (((struct xcoff_link_hash_entry *) h)->flags
& XCOFF_DEF_DYNAMIC) == 0))
{
if (!(*info->callbacks
->add_archive_element) (info, abfd, name, subsbfd))
- return FALSE;
+ continue;
*pneeded = TRUE;
return TRUE;
}
static bfd_boolean
xcoff_link_check_archive_element (bfd *abfd,
struct bfd_link_info *info,
+ struct bfd_link_hash_entry *h ATTRIBUTE_UNUSED,
+ const char *name ATTRIBUTE_UNUSED,
bfd_boolean *pneeded)
{
bfd_boolean keep_syms_p;
bfd_boolean needed;
if (! xcoff_link_check_archive_element (member, info,
- &needed))
+ NULL, NULL, &needed))
return FALSE;
if (needed)
member->archive_pass = -1;
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))
+ if (h != NULL && bfd_is_abs_symbol (&h->root))
return FALSE;
return TRUE;
/* If we're marking an undefined symbol, try find some way of
defining it. */
- if (!info->relocatable
+ if (!bfd_link_relocatable (info)
&& (h->flags & XCOFF_IMPORT) == 0
&& (h->flags & XCOFF_DEF_REGULAR) == 0
&& (h->root.type == bfd_link_hash_undefined
|| o == xcoff_hash_table (info)->loader_section
|| o == xcoff_hash_table (info)->linkage_section
|| o == xcoff_hash_table (info)->descriptor_section
- || (bfd_get_section_flags (sub, o) & SEC_DEBUGGING)
+ || (bfd_section_flags (o) & SEC_DEBUGGING)
|| strcmp (o->name, ".debug") == 0)
o->flags |= SEC_MARK;
else
if (val != (bfd_vma) -1)
{
if (h->root.type == bfd_link_hash_defined
- && (! bfd_is_abs_section (h->root.u.def.section)
+ && (!bfd_is_abs_symbol (&h->root)
|| h->root.u.def.value != val))
- {
- if (! ((*info->callbacks->multiple_definition)
- (info, &h->root, output_bfd, bfd_abs_section_ptr, val)))
- return FALSE;
- }
+ (*info->callbacks->multiple_definition) (info, &h->root, output_bfd,
+ bfd_abs_section_ptr, val);
h->root.type = bfd_link_hash_defined;
h->root.u.def.section = bfd_abs_section_ptr;
FALSE));
if (h == NULL)
{
- (*_bfd_error_handler) (_("%s: no such symbol"), name);
+ _bfd_error_handler (_("%s: no such symbol"), name);
bfd_set_error (bfd_error_no_symbols);
return FALSE;
}
if ((h->flags & XCOFF_EXPORT) != 0
&& (h->flags & XCOFF_WAS_UNDEFINED) != 0)
{
- (*_bfd_error_handler)
+ _bfd_error_handler
(_("warning: attempt to export undefined symbol `%s'"),
h->root.root.string);
return TRUE;
"__rtinit", FALSE, FALSE, TRUE);
if (hsym == NULL)
{
- (*_bfd_error_handler)
+ _bfd_error_handler
(_("error: undefined symbol __rtinit"));
return FALSE;
}
}
/* Garbage collect unused sections. */
- if (info->relocatable || !gc)
+ if (bfd_link_relocatable (info) || !gc)
{
gc = FALSE;
xcoff_hash_table (info)->gc = FALSE;
ldrel.l_symndx = 2;
else
{
- (*_bfd_error_handler)
- (_("%B: loader reloc in unrecognized section `%s'"),
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: loader reloc in unrecognized section `%s'"),
reference_bfd, secname);
bfd_set_error (bfd_error_nonrepresentable_section);
return FALSE;
{
if (h->ldindx < 0)
{
- (*_bfd_error_handler)
- (_("%B: `%s' in loader reloc but not loader sym"),
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: `%s' in loader reloc but not loader sym"),
reference_bfd, h->root.root.string);
bfd_set_error (bfd_error_bad_value);
return FALSE;
if (xcoff_hash_table (flinfo->info)->textro
&& strcmp (output_section->name, ".text") == 0)
{
- (*_bfd_error_handler)
- (_("%B: loader reloc in read-only section %A"),
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: loader reloc in read-only section %pA"),
reference_bfd, output_section);
bfd_set_error (bfd_error_invalid_operation);
return FALSE;
if (! flinfo->info->keep_memory)
copy = TRUE;
hash = TRUE;
- if ((output_bfd->flags & BFD_TRADITIONAL_FORMAT) != 0)
+ if (flinfo->info->traditional_format)
hash = FALSE;
if (! _bfd_coff_get_external_symbols (input_bfd))
if (strings == NULL)
return FALSE;
}
- filename = strings + aux.x_file.x_n.x_offset;
+ if ((bfd_size_type) aux.x_file.x_n.x_offset >= obj_coff_strings_len (input_bfd))
+ filename = _("<corrupt>");
+ else
+ filename = strings + aux.x_file.x_n.x_offset;
indx = _bfd_stringtab_add (flinfo->strtab, filename,
hash, copy);
if (indx == (bfd_size_type) -1)
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)));
+ + ((flinfo->last_file_index - syment_base)
+ * osymesz)));
}
/* Write the modified symbols to the output file. */
this case, but I don't think it's worth it. */
is = flinfo->internal_syms + r_symndx;
- if (is->n_sclass != C_DWARF)
- {
- name = (_bfd_coff_internal_syment_name
- (input_bfd, is, buf));
+ if (is->n_sclass != C_DWARF)
+ {
+ name = (_bfd_coff_internal_syment_name
+ (input_bfd, is, buf));
- if (name == NULL)
- return FALSE;
+ if (name == NULL)
+ return FALSE;
- if (!(*flinfo->info->callbacks->unattached_reloc)
- (flinfo->info, name, input_bfd, o,
- irel->r_vaddr))
- return FALSE;
- }
+ (*flinfo->info->callbacks->unattached_reloc)
+ (flinfo->info, name,
+ input_bfd, o, irel->r_vaddr);
+ }
}
}
}
if ((o->flags & SEC_DEBUGGING) == 0
- && xcoff_need_ldrel_p (flinfo->info, irel, h))
+ && xcoff_need_ldrel_p (flinfo->info, irel, h))
{
asection *sec;
/* Make sure that the start of the TOC is also within range. */
if (best_address > toc_start + 0x8000)
{
- (*_bfd_error_handler)
- (_("TOC overflow: 0x%lx > 0x10000; try -mminimal-toc "
+ _bfd_error_handler
+ (_("TOC overflow: %#" PRIx64 " > 0x10000; try -mminimal-toc "
"when compiling"),
- (unsigned long) (toc_end - toc_start));
+ (uint64_t) (toc_end - toc_start));
bfd_set_error (bfd_error_file_too_big);
return FALSE;
}
xcoff_data (output_bfd)->sntoc = section_index;
/* Fill out the TC0 symbol. */
- if (!bfd_xcoff_put_symbol_name (output_bfd, flinfo->strtab, &irsym, "TOC"))
+ if (!bfd_xcoff_put_symbol_name (output_bfd, flinfo->info, flinfo->strtab,
+ &irsym, "TOC"))
return FALSE;
irsym.n_value = best_address;
irsym.n_scnum = section_index;
tocoff += h->descriptor->u.toc_offset;
/* The first instruction in the glink code needs to be
- cooked to to hold the correct offset in the toc. The
+ cooked to hold the correct offset in the toc. The
rest are just output raw. */
bfd_put_32 (output_bfd,
bfd_xcoff_glink_code(output_bfd, 0) | (tocoff & 0xffff), p);
the reloc. */
if (flinfo->info->strip != strip_all)
{
- result = bfd_xcoff_put_symbol_name (output_bfd, flinfo->strtab,
+ result = bfd_xcoff_put_symbol_name (output_bfd, flinfo->info,
+ flinfo->strtab,
&irsym, h->root.root.string);
if (!result)
return FALSE;
h->indx = obj_raw_syment_count (output_bfd);
- result = bfd_xcoff_put_symbol_name (output_bfd, flinfo->strtab, &isym,
- h->root.root.string);
+ result = bfd_xcoff_put_symbol_name (output_bfd, flinfo->info, flinfo->strtab,
+ &isym, h->root.root.string);
if (!result)
return FALSE;
|| h->root.type == bfd_link_hash_defweak)
&& h->smclas == XMC_XO)
{
- BFD_ASSERT (bfd_is_abs_section (h->root.u.def.section));
+ BFD_ASSERT (bfd_is_abs_symbol (&h->root));
isym.n_value = h->root.u.def.value;
isym.n_scnum = N_UNDEF;
- if (h->root.type == bfd_link_hash_undefweak
+ if (h->root.type == bfd_link_hash_defweak
&& C_WEAKEXT == C_AIX_WEAKEXT)
isym.n_sclass = C_WEAKEXT;
else
/* We just output an SD symbol. Now output an LD symbol. */
h->indx += 2;
- if (h->root.type == bfd_link_hash_undefweak
+ if (h->root.type == bfd_link_hash_defweak
&& C_WEAKEXT == C_AIX_WEAKEXT)
isym.n_sclass = C_WEAKEXT;
else
FALSE, FALSE, TRUE));
if (h == NULL)
{
- if (! ((*flinfo->info->callbacks->unattached_reloc)
- (flinfo->info, link_order->u.reloc.p->u.name, NULL, NULL, (bfd_vma) 0)))
- return FALSE;
+ (*flinfo->info->callbacks->unattached_reloc)
+ (flinfo->info, link_order->u.reloc.p->u.name, NULL, NULL, (bfd_vma) 0);
return TRUE;
}
size = bfd_get_reloc_size (howto);
buf = bfd_zmalloc (size);
- if (buf == NULL)
+ if (buf == NULL && size != 0)
return FALSE;
rstat = _bfd_relocate_contents (howto, output_bfd, addend, buf);
case bfd_reloc_outofrange:
abort ();
case bfd_reloc_overflow:
- 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);
- return FALSE;
- }
+ (*flinfo->info->callbacks->reloc_overflow)
+ (flinfo->info, NULL, link_order->u.reloc.p->u.name,
+ howto->name, addend, NULL, NULL, (bfd_vma) 0);
break;
}
ok = bfd_set_section_contents (output_bfd, output_section, (void *) buf,
file_ptr pos;
bfd_size_type amt;
- if (info->shared)
+ if (bfd_link_pic (info))
abfd->flags |= DYNAMIC;
symesz = bfd_coff_symesz (abfd);
{
if ((*rel_hash)->indx < 0)
{
- if (! ((*info->callbacks->unattached_reloc)
- (info, (*rel_hash)->root.root.string,
- NULL, o, irel->r_vaddr)))
- goto error_return;
+ (*info->callbacks->unattached_reloc)
+ (info, (*rel_hash)->root.root.string,
+ NULL, o, irel->r_vaddr);
(*rel_hash)->indx = 0;
}
irel->r_symndx = (*rel_hash)->indx;
{
if (toc_rel_hash->h->u.toc_indx < 0)
{
- if (! ((*info->callbacks->unattached_reloc)
- (info, toc_rel_hash->h->root.root.string,
- NULL, o, toc_rel_hash->rel->r_vaddr)))
- goto error_return;
+ (*info->callbacks->unattached_reloc)
+ (info, toc_rel_hash->h->root.root.string,
+ NULL, o, toc_rel_hash->rel->r_vaddr);
toc_rel_hash->h->u.toc_indx = 0;
}
toc_rel_hash->rel->r_symndx = toc_rel_hash->h->u.toc_indx;
goto error_return;
}
- /* Setting bfd_get_symcount to 0 will cause write_object_contents to
+ /* Setting symcount to 0 will cause write_object_contents to
not try to write out the symbols. */
- bfd_get_symcount (abfd) = 0;
+ abfd->symcount = 0;
return TRUE;