/* MMIX-specific support for 64-bit ELF.
- Copyright (C) 2001-2016 Free Software Foundation, Inc.
+ Copyright (C) 2001-2019 Free Software Foundation, Inc.
Contributed by Hans-Peter Nilsson <hp@bitrange.com>
This file is part of BFD, the Binary File Descriptor library.
/* Only intended to be called from a debugger. */
extern void mmix_dump_bpo_gregs
- (struct bfd_link_info *, bfd_error_handler_type);
+ (struct bfd_link_info *, void (*) (const char *, ...));
static void
mmix_set_relaxable_size (bfd *, asection *, void *);
FALSE, /* partial_inplace */
~0x0100ffff, /* src_mask */
0x0100ffff, /* dst_mask */
- TRUE), /* pcrel_offset */
+ TRUE), /* pcrel_offset */
HOWTO (R_MMIX_CBRANCH_J, /* type */
2, /* rightshift */
a verbose message. */
*error_message
= _("invalid input relocation when producing"
- " non-ELF, non-mmo format output."
- "\n Please use the objcopy program to convert from"
+ " non-ELF, non-mmo format output;"
+ " please use the objcopy program to convert from"
" ELF or mmo,"
- "\n or assemble using"
+ " or assemble using"
" \"-no-expand\" (for gcc, \"-Wa,-no-expand\"");
mmix_elf_section_data (isec)->has_warned_pushj = TRUE;
return bfd_reloc_dangerous;
a verbose message. */
*error_message
= _("invalid input relocation when producing"
- " non-ELF, non-mmo format output."
- "\n Please use the objcopy program to convert from"
+ " non-ELF, non-mmo format output;"
+ " please use the objcopy program to convert from"
" ELF or mmo,"
- "\n or compile using the gcc-option"
+ " or compile using the gcc-option"
" \"-mno-base-addresses\".");
mmix_elf_section_data (isec)->has_warned_bpo = TRUE;
return bfd_reloc_dangerous;
doesn't cost much, so can be left in at all times. */
if (value != gregdata->reloc_request[bpo_index].value)
{
- (*_bfd_error_handler)
- (_("%s: Internal inconsistency error for value for\n\
- linker-allocated global register: linked: 0x%lx%08lx != relaxed: 0x%lx%08lx\n"),
- bfd_get_filename (isec->owner),
- (unsigned long) (value >> 32), (unsigned long) value,
- (unsigned long) (gregdata->reloc_request[bpo_index].value
- >> 32),
- (unsigned long) gregdata->reloc_request[bpo_index].value);
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: Internal inconsistency error for value for\n\
+ linker-allocated global register: linked: %#" PRIx64 " != relaxed: %#" PRIx64 ""),
+ isec->owner,
+ (uint64_t) value,
+ (uint64_t) gregdata->reloc_request[bpo_index].value);
bfd_set_error (bfd_error_bad_value);
return bfd_reloc_overflow;
}
/* Set the howto pointer for an MMIX ELF reloc (type RELA). */
-static void
-mmix_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED,
+static bfd_boolean
+mmix_info_to_howto_rela (bfd *abfd,
arelent *cache_ptr,
Elf_Internal_Rela *dst)
{
r_type = ELF64_R_TYPE (dst->r_info);
if (r_type >= (unsigned int) R_MMIX_max)
{
- _bfd_error_handler (_("%B: invalid MMIX reloc number: %d"), abfd, r_type);
- r_type = 0;
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
+ abfd, r_type);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
}
cache_ptr->howto = &elf_mmix_howto_table[r_type];
+ return TRUE;
}
/* Any MMIX-specific relocation gets here at assembly time or when linking
else
relocation = symbol->value;
- reloc_target_output_section = bfd_get_output_section (symbol);
+ reloc_target_output_section = bfd_asymbol_section (symbol)->output_section;
/* Here the variable relocation holds the final address of the symbol we
are relocating against, plus any addend. */
symtab_hdr->sh_link,
sym->st_name);
if (name == NULL)
- name = bfd_section_name (input_bfd, sec);
+ name = bfd_section_name (sec);
}
else
{
return bfd_reloc_undefined;
/* Check that we're not relocating against a register symbol. */
- if (strcmp (bfd_get_section_name (symsec->owner, symsec),
+ if (strcmp (bfd_section_name (symsec),
MMIX_REG_CONTENTS_SECTION_NAME) == 0
- || strcmp (bfd_get_section_name (symsec->owner, symsec),
+ || strcmp (bfd_section_name (symsec),
MMIX_REG_SECTION_NAME) == 0)
{
/* Note: This is separated out into two messages in order
to ease the translation into other languages. */
if (symname == NULL || *symname == 0)
- (*_bfd_error_handler)
- (_("%s: base-plus-offset relocation against register symbol: (unknown) in %s"),
- bfd_get_filename (input_section->owner),
- bfd_get_section_name (symsec->owner, symsec));
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: base-plus-offset relocation against register symbol:"
+ " (unknown) in %pA"),
+ input_section->owner, symsec);
else
- (*_bfd_error_handler)
- (_("%s: base-plus-offset relocation against register symbol: %s in %s"),
- bfd_get_filename (input_section->owner), symname,
- bfd_get_section_name (symsec->owner, symsec));
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: base-plus-offset relocation against register symbol:"
+ " %s in %pA"),
+ input_section->owner, symname, symsec);
return bfd_reloc_overflow;
}
goto do_mmix_reloc;
if (symsec == NULL)
return bfd_reloc_undefined;
- if (strcmp (bfd_get_section_name (symsec->owner, symsec),
+ if (strcmp (bfd_section_name (symsec),
MMIX_REG_CONTENTS_SECTION_NAME) == 0)
{
if ((srel & 7) != 0 || srel < 32*8 || srel > 255*8)
}
srel /= 8;
}
- else if (strcmp (bfd_get_section_name (symsec->owner, symsec),
+ else if (strcmp (bfd_section_name (symsec),
MMIX_REG_SECTION_NAME) == 0)
{
if (srel < 0 || srel > 255)
/* Note: This is separated out into two messages in order
to ease the translation into other languages. */
if (symname == NULL || *symname == 0)
- (*_bfd_error_handler)
- (_("%s: register relocation against non-register symbol: (unknown) in %s"),
- bfd_get_filename (input_section->owner),
- bfd_get_section_name (symsec->owner, symsec));
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: register relocation against non-register symbol:"
+ " (unknown) in %pA"),
+ input_section->owner, symsec);
else
- (*_bfd_error_handler)
- (_("%s: register relocation against non-register symbol: %s in %s"),
- bfd_get_filename (input_section->owner), symname,
- bfd_get_section_name (symsec->owner, symsec));
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: register relocation against non-register symbol:"
+ " %s in %pA"),
+ input_section->owner, symname, symsec);
/* The bfd_reloc_outofrange return value, though intuitively a
better value, will not get us an error. */
accidentally handling it. */
if (!bfd_is_abs_section (symsec)
&& !bfd_is_und_section (symsec)
- && strcmp (bfd_get_section_name (symsec->owner, symsec),
+ && strcmp (bfd_section_name (symsec),
MMIX_REG_CONTENTS_SECTION_NAME) != 0
- && strcmp (bfd_get_section_name (symsec->owner, symsec),
+ && strcmp (bfd_section_name (symsec),
MMIX_REG_SECTION_NAME) != 0)
{
- (*_bfd_error_handler)
- (_("%s: directive LOCAL valid only with a register or absolute value"),
- bfd_get_filename (input_section->owner));
+ _bfd_error_handler
+ (_("%pB: directive LOCAL valid only with a register or absolute value"),
+ input_section->owner);
return bfd_reloc_overflow;
}
first_global = 255;
else
{
- first_global
- = bfd_get_section_vma (input_section->output_section->owner,
- regsec) / 8;
- if (strcmp (bfd_get_section_name (symsec->owner, symsec),
+ first_global = bfd_section_vma (regsec) / 8;
+ if (strcmp (bfd_section_name (symsec),
MMIX_REG_CONTENTS_SECTION_NAME) == 0)
{
if ((srel & 7) != 0 || srel < 32*8 || srel > 255*8)
if ((bfd_vma) srel >= first_global)
{
/* FIXME: Better error message. */
- (*_bfd_error_handler)
- (_("%s: LOCAL directive: Register $%ld is not a local register. First global register is $%ld."),
- bfd_get_filename (input_section->owner), (long) srel, (long) first_global);
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: LOCAL directive: "
+ "register $%" PRId64 " is not a local register;"
+ " first global register is $%" PRId64),
+ input_section->owner, (int64_t) srel, (int64_t) first_global);
return bfd_reloc_overflow;
}
return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
}
-
-/* Update relocation info for a GC-excluded section. We could supposedly
- perform the allocation after GC, but there's no suitable hook between
- GC (or section merge) and the point when all input sections must be
- present. Better to waste some memory and (perhaps) a little time. */
-
-static bfd_boolean
-mmix_elf_gc_sweep_hook (bfd *abfd ATTRIBUTE_UNUSED,
- struct bfd_link_info *info ATTRIBUTE_UNUSED,
- asection *sec,
- const Elf_Internal_Rela *relocs ATTRIBUTE_UNUSED)
-{
- struct bpo_reloc_section_info *bpodata
- = mmix_elf_section_data (sec)->bpo.reloc;
- asection *allocated_gregs_section;
-
- /* If no bpodata here, we have nothing to do. */
- if (bpodata == NULL)
- return TRUE;
-
- allocated_gregs_section = bpodata->bpo_greg_section;
-
- mmix_elf_section_data (allocated_gregs_section)->bpo.greg->n_bpo_relocs
- -= bpodata->n_bpo_relocs_this_section;
-
- return TRUE;
-}
\f
/* Sort register relocs to come before expanding relocs. */
for (rel = relocs; rel < rel_end; rel++)
{
switch (ELF64_R_TYPE (rel->r_info))
- {
+ {
/* This relocation causes a GREG allocation. We need to count
them, and we need to create a section for them, so we need an
object to fake as the owner of that section. We can't use
those flags, as that is what currently happens for usual
GREG allocations, and that works. */
if (allocated_gregs_section == NULL
- || !bfd_set_section_alignment (bpo_greg_owner,
- allocated_gregs_section,
- 3))
+ || !bfd_set_section_alignment (allocated_gregs_section, 3))
return FALSE;
gregdata = (struct bpo_greg_section_info *)
r_symndx = ELF64_R_SYM (rel->r_info);
if (r_symndx < symtab_hdr->sh_info)
- h = NULL;
+ h = NULL;
else
{
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
while (h->root.type == bfd_link_hash_indirect
|| h->root.type == bfd_link_hash_warning)
h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
- /* PR15323, ref flags aren't set for references in the same
- object. */
- h->root.non_ir_ref = 1;
}
switch (ELF64_R_TYPE (rel->r_info))
{
- /* This relocation describes the C++ object vtable hierarchy.
- Reconstruct it for later use during GC. */
- case R_MMIX_GNU_VTINHERIT:
- if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
- return FALSE;
- break;
-
- /* This relocation describes which C++ vtable entries are actually
- used. Record for later use during GC. */
- case R_MMIX_GNU_VTENTRY:
- BFD_ASSERT (h != NULL);
- if (h != NULL
- && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
- return FALSE;
- break;
+ /* This relocation describes the C++ object vtable hierarchy.
+ Reconstruct it for later use during GC. */
+ case R_MMIX_GNU_VTINHERIT:
+ if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
+ return FALSE;
+ break;
+
+ /* This relocation describes which C++ vtable entries are actually
+ used. Record for later use during GC. */
+ case R_MMIX_GNU_VTENTRY:
+ if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
+ return FALSE;
+ break;
}
}
asection * sec,
int * retval)
{
- if (strcmp (bfd_get_section_name (abfd, sec), MMIX_REG_SECTION_NAME) == 0)
+ if (strcmp (bfd_section_name (sec), MMIX_REG_SECTION_NAME) == 0)
*retval = SHN_REGISTER;
else
return FALSE;
{
/* How do we get the asymbol (or really: the filename) from h?
h->u.def.section->owner is NULL. */
- ((*_bfd_error_handler)
- (_("%s: Error: multiple definition of `%s'; start of %s is set in a earlier linked file\n"),
- bfd_get_filename (abfd), *namep,
- *namep + strlen (MMIX_LOC_SECTION_START_SYMBOL_PREFIX)));
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: error: multiple definition of `%s'; start of %s "
+ "is set in a earlier linked file"),
+ abfd, *namep,
+ *namep + strlen (MMIX_LOC_SECTION_START_SYMBOL_PREFIX));
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
if (reg_section != NULL)
{
/* FIXME: Pass error state gracefully. */
- if (bfd_get_section_flags (abfd, reg_section) & SEC_HAS_CONTENTS)
- _bfd_abort (__FILE__, __LINE__, _("Register section has contents\n"));
+ if (bfd_section_flags (reg_section) & SEC_HAS_CONTENTS)
+ _bfd_abort (__FILE__, __LINE__, _("register section has contents\n"));
/* Really remove the section, if it hasn't already been done. */
if (!bfd_section_removed_from_list (abfd, reg_section))
/* Set the zeroth-order estimate for the GREGs size. */
gregs_size = n_gregs * 8;
- if (!bfd_set_section_size (bpo_greg_owner, bpo_gregs_section, gregs_size))
+ if (!bfd_set_section_size (bpo_gregs_section, gregs_size))
return FALSE;
/* Allocate and set up the GREG arrays. They're filled in at relaxation
if (gregdata->n_remaining_bpo_relocs_this_relaxation_round
!= gregdata->n_bpo_relocs)
{
- (*_bfd_error_handler)
- (_("Internal inconsistency: remaining %u != max %u.\n\
- Please report this bug."),
- gregdata->n_remaining_bpo_relocs_this_relaxation_round,
- gregdata->n_bpo_relocs);
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("internal inconsistency: remaining %lu != max %lu;"
+ " please report this bug"),
+ (unsigned long) gregdata->n_remaining_bpo_relocs_this_relaxation_round,
+ (unsigned long) gregdata->n_bpo_relocs);
return FALSE;
}
void
mmix_dump_bpo_gregs (struct bfd_link_info *link_info,
- bfd_error_handler_type pf)
+ void (*pf) (const char *fmt, ...))
{
bfd *bpo_greg_owner;
asection *bpo_gregs_section;
|| (sec->flags & SEC_CODE) == 0
|| (sec->flags & SEC_LINKER_CREATED) != 0
/* If no R_MMIX_BASE_PLUS_OFFSET relocs and no PUSHJ-stub relocs,
- then nothing to do. */
+ then nothing to do. */
|| (bpodata == NULL
&& mmix_elf_section_data (sec)->pjs.n_pushj_relocs == 0))
return TRUE;
indx = ELF64_R_SYM (irel->r_info) - symtab_hdr->sh_info;
h = elf_sym_hashes (abfd)[indx];
BFD_ASSERT (h != NULL);
- if (h->root.type != bfd_link_hash_defined
- && h->root.type != bfd_link_hash_defweak)
+ if (h->root.type == bfd_link_hash_undefweak)
+ /* FIXME: for R_MMIX_PUSHJ_STUBBABLE, there are alternatives to
+ the canonical value 0 for an unresolved weak symbol to
+ consider: as the debug-friendly approach, resolve to "abort"
+ (or a port-specific function), or as the space-friendly
+ approach resolve to the next instruction (like some other
+ ports, notably ARM and AArch64). These alternatives require
+ matching code in mmix_elf_perform_relocation or its caller. */
+ symval = 0;
+ else if (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ symval = (h->root.u.def.value
+ + h->root.u.def.section->output_section->vma
+ + h->root.u.def.section->output_offset);
+ else
{
/* This appears to be a reference to an undefined symbol. Just
ignore it--it will be caught by the regular reloc processing.
}
continue;
}
-
- symval = (h->root.u.def.value
- + h->root.u.def.section->output_section->vma
- + h->root.u.def.section->output_offset);
}
if (ELF64_R_TYPE (irel->r_info) == (int) R_MMIX_PUSHJ_STUBBABLE)
}
}
+ BFD_ASSERT(pjsno == mmix_elf_section_data (sec)->pjs.n_pushj_relocs);
+
if (internal_relocs != NULL
&& elf_section_data (sec)->relocs != internal_relocs)
free (internal_relocs);
}
\f
#define ELF_ARCH bfd_arch_mmix
-#define ELF_MACHINE_CODE EM_MMIX
+#define ELF_MACHINE_CODE EM_MMIX
/* According to mmix-doc page 36 (paragraph 45), this should be (1LL << 48LL).
However, that's too much for something somewhere in the linker part of
#define elf_info_to_howto mmix_info_to_howto_rela
#define elf_backend_relocate_section mmix_elf_relocate_section
#define elf_backend_gc_mark_hook mmix_elf_gc_mark_hook
-#define elf_backend_gc_sweep_hook mmix_elf_gc_sweep_hook
#define elf_backend_link_output_symbol_hook \
mmix_elf_link_output_symbol_hook
#define elf_backend_check_relocs mmix_elf_check_relocs
#define elf_backend_symbol_processing mmix_elf_symbol_processing
-#define elf_backend_omit_section_dynsym \
- ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true)
+#define elf_backend_omit_section_dynsym _bfd_elf_omit_section_dynsym_all
+
+#define bfd_elf64_bfd_copy_link_hash_symbol_type \
+ _bfd_generic_copy_link_hash_symbol_type
#define bfd_elf64_bfd_is_local_label_name \
mmix_elf_is_local_label_name