Back to index

cell-binutils  2.17cvs20070401
Classes | Defines | Functions | Variables
elf64-mmix.c File Reference
#include "bfd.h"
#include "sysdep.h"
#include "libbfd.h"
#include "elf-bfd.h"
#include "elf/mmix.h"
#include "opcode/mmix.h"
#include "elf64-target.h"

Go to the source code of this file.

Classes

struct  _mmix_elf_section_data
struct  _mmix_elf_section_data::pushj_stub_info
struct  bpo_reloc_request
struct  mmix_reloc_map
union  _mmix_elf_section_data.bpo

Defines

#define MINUS_ONE   (((bfd_vma) 0) - 1)
#define MAX_PUSHJ_STUB_SIZE   (5 * 4)
#define FATAL_DEBUG
#define BAD_CASE(x)
#define mmix_elf_section_data(sec)   ((struct _mmix_elf_section_data *) elf_section_data (sec))
#define ELF_ARCH   bfd_arch_mmix
#define ELF_MACHINE_CODE   EM_MMIX
#define ELF_MAXPAGESIZE   0x100
#define TARGET_BIG_SYM   bfd_elf64_mmix_vec
#define TARGET_BIG_NAME   "elf64-mmix"
#define elf_info_to_howto_rel   NULL
#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_add_symbol_hook   mmix_elf_add_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 bfd_elf64_bfd_is_local_label_name   mmix_elf_is_local_label_name
#define elf_backend_may_use_rel_p   0
#define elf_backend_may_use_rela_p   1
#define elf_backend_default_use_rela_p   1
#define elf_backend_can_gc_sections   1
#define elf_backend_section_from_bfd_section   mmix_elf_section_from_bfd_section
#define bfd_elf64_new_section_hook   mmix_elf_new_section_hook
#define bfd_elf64_bfd_final_link   mmix_elf_final_link
#define bfd_elf64_bfd_relax_section   mmix_elf_relax_section

Functions

static bfd_boolean
mmix_elf_link_output_symbol_hook 
PARAMS ((struct bfd_link_info *, const char *, Elf_Internal_Sym *, asection *, struct elf_link_hash_entry *))
static bfd_reloc_status_type
mmix_elf_reloc 
PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **))
static reloc_howto_type
*bfd_elf64_bfd_reloc_type_lookup 
PARAMS ((bfd *, bfd_reloc_code_real_type))
static void mmix_info_to_howto_rela PARAMS ((bfd *, arelent *, Elf_Internal_Rela *))
static int mmix_elf_sort_relocs PARAMS ((const PTR, const PTR))
static bfd_boolean
mmix_elf_new_section_hook 
PARAMS ((bfd *, asection *))
static bfd_boolean
mmix_elf_check_relocs 
PARAMS ((bfd *, struct bfd_link_info *, asection *, const Elf_Internal_Rela *))
static bfd_boolean
mmix_elf_relocate_section 
PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, Elf_Internal_Rela *, Elf_Internal_Sym *, asection **))
static bfd_reloc_status_type
mmix_final_link_relocate 
PARAMS ((reloc_howto_type *, asection *, bfd_byte *, bfd_vma, bfd_signed_vma, bfd_vma, const char *, asection *))
static bfd_reloc_status_type
mmix_elf_perform_relocation 
PARAMS ((asection *, reloc_howto_type *, PTR, bfd_vma, bfd_vma))
static bfd_boolean
mmix_elf_section_from_bfd_section 
PARAMS ((bfd *, asection *, int *))
static bfd_boolean
mmix_elf_add_symbol_hook 
PARAMS ((bfd *, struct bfd_link_info *, Elf_Internal_Sym *, const char **, flagword *, asection **, bfd_vma *))
static bfd_boolean
mmix_elf_is_local_label_name 
PARAMS ((bfd *, const char *))
static bfd_boolean
mmix_elf_relax_section 
PARAMS ((bfd *abfd, asection *sec, struct bfd_link_info *link_info, bfd_boolean *again))
bfd_boolean mmix_elf_final_link PARAMS ((bfd *, struct bfd_link_info *))
void mmix_elf_symbol_processing PARAMS ((bfd *, asymbol *))
void mmix_dump_bpo_gregs PARAMS ((struct bfd_link_info *, bfd_error_handler_type))
static void mmix_set_relaxable_size PARAMS ((bfd *, asection *, void *))
static reloc_howto_type * bfd_elf64_bfd_reloc_type_lookup (abfd, bfd_reloc_code_real_type code)
static reloc_howto_type * bfd_elf64_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name)
static bfd_boolean mmix_elf_new_section_hook (bfd *abfd, asection *sec)
static bfd_reloc_status_type mmix_elf_perform_relocation (asection *isec, reloc_howto_type *howto, PTR datap, bfd_vma addr, bfd_vma value)
static void mmix_info_to_howto_rela (abfd, arelent *cache_ptr, Elf_Internal_Rela *dst)
static bfd_reloc_status_type mmix_elf_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, PTR data, asection *input_section, bfd *output_bfd, error_message)
static bfd_boolean mmix_elf_relocate_section (output_bfd, struct bfd_link_info *info, bfd *input_bfd, asection *input_section, bfd_byte *contents, Elf_Internal_Rela *relocs, Elf_Internal_Sym *local_syms, asection **local_sections)
static bfd_reloc_status_type mmix_final_link_relocate (reloc_howto_type *howto, asection *input_section, bfd_byte *contents, bfd_vma r_offset, bfd_signed_vma r_addend, bfd_vma relocation, const char *symname, asection *symsec)
static asectionmmix_elf_gc_mark_hook (asection *sec, struct bfd_link_info *info, Elf_Internal_Rela *rel, struct elf_link_hash_entry *h, Elf_Internal_Sym *sym)
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)
static int mmix_elf_sort_relocs (PTR p1, const PTR p2) const
static bfd_boolean mmix_elf_check_common_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec, const Elf_Internal_Rela *relocs)
static bfd_boolean mmix_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec, const Elf_Internal_Rela *relocs)
bfd_boolean _bfd_mmix_check_all_relocs (bfd *abfd, struct bfd_link_info *info)
static bfd_boolean mmix_elf_link_output_symbol_hook (info, name, Elf_Internal_Sym *sym, asection *input_sec, h)
void mmix_elf_symbol_processing (abfd, asymbol *asym)
static bfd_boolean mmix_elf_section_from_bfd_section (abfd, asection *sec, int *retval)
bfd_boolean mmix_elf_add_symbol_hook (bfd *abfd, info, Elf_Internal_Sym *sym, namep, flagsp, asection **secp, valp)
bfd_boolean mmix_elf_is_local_label_name (bfd *abfd, const char *name)
bfd_boolean mmix_elf_final_link (bfd *abfd, struct bfd_link_info *info)
static void mmix_set_relaxable_size (abfd, asection *sec, void *ptr)
bfd_boolean _bfd_mmix_before_linker_allocation (abfd, struct bfd_link_info *info)
bfd_boolean _bfd_mmix_after_linker_allocation (abfd, struct bfd_link_info *link_info)
static int bpo_reloc_request_sort_fn (PTR p1, const PTR p2) const
void mmix_dump_bpo_gregs (struct bfd_link_info *link_info, bfd_error_handler_type pf)
static bfd_boolean mmix_elf_relax_section (bfd *abfd, asection *sec, struct bfd_link_info *link_info, bfd_boolean *again)

Variables

static reloc_howto_type elf_mmix_howto_table []
static struct mmix_reloc_map []
static asection mmix_elf_reg_section
static asymbol mmix_elf_reg_section_symbol
static asymbolmmix_elf_reg_section_symbol_ptr

Class Documentation

struct _mmix_elf_section_data

Definition at line 50 of file elf64-mmix.c.

Collaboration diagram for _mmix_elf_section_data:
Class Members
union _mmix_elf_section_data bpo
struct pushj_stub_info pjs
struct _mmix_elf_section_data::pushj_stub_info

Definition at line 59 of file elf64-mmix.c.

Class Members
bfd_size_type n_pushj_relocs
bfd_size_type stub_offset
bfd_size_type * stub_size
bfd_size_type stubs_size_sum
struct bpo_reloc_section_info

Definition at line 84 of file elf64-mmix.c.

Collaboration diagram for bpo_reloc_section_info:
Class Members
asection * bpo_greg_section
size_t bpo_index
size_t first_base_plus_offset_reloc
size_t n_bpo_relocs_this_section
struct bpo_reloc_request

Definition at line 103 of file elf64-mmix.c.

Class Members
size_t bpo_reloc_no
size_t offset
size_t regindex
bfd_boolean valid
bfd_vma value
struct bpo_greg_section_info

Definition at line 129 of file elf64-mmix.c.

Collaboration diagram for bpo_greg_section_info:
Class Members
size_t * bpo_reloc_indexes
size_t n_allocated_bpo_gregs
size_t n_bpo_relocs
size_t n_max_bpo_relocs
size_t n_remaining_bpo_relocs_this_relaxation_round
struct bpo_reloc_request * reloc_request
struct mmix_reloc_map

Definition at line 798 of file elf64-mmix.c.

Class Members
bfd_reloc_code_real_type bfd_reloc_val
union _mmix_elf_section_data.bpo

Definition at line 53 of file elf64-mmix.c.

Class Members
struct bpo_greg_section_info * greg
struct bpo_reloc_section_info * reloc

Define Documentation

#define BAD_CASE (   x)
Value:
_bfd_abort (__FILE__, __LINE__,           \
            "bad case for " #x)

Definition at line 46 of file elf64-mmix.c.

Definition at line 2952 of file elf64-mmix.c.

Definition at line 2940 of file elf64-mmix.c.

Definition at line 2953 of file elf64-mmix.c.

Definition at line 2951 of file elf64-mmix.c.

#define ELF_ARCH   bfd_arch_mmix

Definition at line 2905 of file elf64-mmix.c.

Definition at line 2933 of file elf64-mmix.c.

Definition at line 2947 of file elf64-mmix.c.

Definition at line 2935 of file elf64-mmix.c.

Definition at line 2945 of file elf64-mmix.c.

Definition at line 2928 of file elf64-mmix.c.

Definition at line 2929 of file elf64-mmix.c.

Definition at line 2931 of file elf64-mmix.c.

#define elf_backend_may_use_rel_p   0

Definition at line 2943 of file elf64-mmix.c.

Definition at line 2944 of file elf64-mmix.c.

Definition at line 2937 of file elf64-mmix.c.

Definition at line 2927 of file elf64-mmix.c.

Definition at line 2948 of file elf64-mmix.c.

Definition at line 2936 of file elf64-mmix.c.

Definition at line 2926 of file elf64-mmix.c.

Definition at line 2925 of file elf64-mmix.c.

#define ELF_MACHINE_CODE   EM_MMIX

Definition at line 2906 of file elf64-mmix.c.

#define ELF_MAXPAGESIZE   0x100

Definition at line 2920 of file elf64-mmix.c.

#define FATAL_DEBUG
Value:
_bfd_abort (__FILE__, __LINE__,                         \
            "Internal: Non-debugged code (test-case missing)")

Definition at line 42 of file elf64-mmix.c.

#define MAX_PUSHJ_STUB_SIZE   (5 * 4)

Definition at line 39 of file elf64-mmix.c.

#define MINUS_ONE   (((bfd_vma) 0) - 1)

Definition at line 37 of file elf64-mmix.c.

Definition at line 78 of file elf64-mmix.c.

#define TARGET_BIG_NAME   "elf64-mmix"

Definition at line 2923 of file elf64-mmix.c.

Definition at line 2922 of file elf64-mmix.c.


Function Documentation

Definition at line 2400 of file elf64-mmix.c.

{
  asection *bpo_gregs_section;
  bfd *bpo_greg_owner;
  struct bpo_greg_section_info *gregdata;
  size_t n_gregs;
  size_t i, j;
  size_t lastreg;
  bfd_byte *contents;

  /* The bpo_greg_owner bfd is supposed to have been set by mmix_elf_check_relocs
     when the first R_MMIX_BASE_PLUS_OFFSET is seen.  If there is no such
     object, there was no R_MMIX_BASE_PLUS_OFFSET.  */
  bpo_greg_owner = (bfd *) link_info->base_file;
  if (bpo_greg_owner == NULL)
    return TRUE;

  bpo_gregs_section
    = bfd_get_section_by_name (bpo_greg_owner,
                            MMIX_LD_ALLOCATED_REG_CONTENTS_SECTION_NAME);

  /* This can't happen without DSO handling.  When DSOs are handled
     without any R_MMIX_BASE_PLUS_OFFSET seen, there will be no such
     section.  */
  if (bpo_gregs_section == NULL)
    return TRUE;

  /* We use the target-data handle in the ELF section data.  */

  gregdata = mmix_elf_section_data (bpo_gregs_section)->bpo.greg;
  if (gregdata == NULL)
    return FALSE;

  n_gregs = gregdata->n_allocated_bpo_gregs;

  bpo_gregs_section->contents
    = contents = bfd_alloc (bpo_greg_owner, bpo_gregs_section->size);
  if (contents == NULL)
    return FALSE;

  /* Sanity check: If these numbers mismatch, some relocation has not been
     accounted for and the rest of gregdata is probably inconsistent.
     It's a bug, but it's more helpful to identify it than segfaulting
     below.  */
  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);
      return FALSE;
    }

  for (lastreg = 255, i = 0, j = 0; j < n_gregs; i++)
    if (gregdata->reloc_request[i].regindex != lastreg)
      {
       bfd_put_64 (bpo_greg_owner, gregdata->reloc_request[i].value,
                  contents + j * 8);
       lastreg = gregdata->reloc_request[i].regindex;
       j++;
      }

  return TRUE;
}

Here is the call graph for this function:

Definition at line 2321 of file elf64-mmix.c.

{
  asection *bpo_gregs_section;
  bfd *bpo_greg_owner;
  struct bpo_greg_section_info *gregdata;
  size_t n_gregs;
  bfd_vma gregs_size;
  size_t i;
  size_t *bpo_reloc_indexes;
  bfd *ibfd;

  /* Set the initial size of sections.  */
  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
    bfd_map_over_sections (ibfd, mmix_set_relaxable_size, info);

  /* The bpo_greg_owner bfd is supposed to have been set by
     mmix_elf_check_relocs when the first R_MMIX_BASE_PLUS_OFFSET is seen.
     If there is no such object, there was no R_MMIX_BASE_PLUS_OFFSET.  */
  bpo_greg_owner = (bfd *) info->base_file;
  if (bpo_greg_owner == NULL)
    return TRUE;

  bpo_gregs_section
    = bfd_get_section_by_name (bpo_greg_owner,
                            MMIX_LD_ALLOCATED_REG_CONTENTS_SECTION_NAME);

  if (bpo_gregs_section == NULL)
    return TRUE;

  /* We use the target-data handle in the ELF section data.  */
  gregdata = mmix_elf_section_data (bpo_gregs_section)->bpo.greg;
  if (gregdata == NULL)
    return FALSE;

  n_gregs = gregdata->n_bpo_relocs;
  gregdata->n_allocated_bpo_gregs = n_gregs;

  /* When this reaches zero during relaxation, all entries have been
     filled in and the size of the linker gregs can be calculated.  */
  gregdata->n_remaining_bpo_relocs_this_relaxation_round = n_gregs;

  /* 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))
    return FALSE;

  /* Allocate and set up the GREG arrays.  They're filled in at relaxation
     time.  Note that we must use the max number ever noted for the array,
     since the index numbers were created before GC.  */
  gregdata->reloc_request
    = bfd_zalloc (bpo_greg_owner,
                sizeof (struct bpo_reloc_request)
                * gregdata->n_max_bpo_relocs);

  gregdata->bpo_reloc_indexes
    = bpo_reloc_indexes
    = bfd_alloc (bpo_greg_owner,
               gregdata->n_max_bpo_relocs
               * sizeof (size_t));
  if (bpo_reloc_indexes == NULL)
    return FALSE;

  /* The default order is an identity mapping.  */
  for (i = 0; i < gregdata->n_max_bpo_relocs; i++)
    {
      bpo_reloc_indexes[i] = i;
      gregdata->reloc_request[i].bpo_reloc_no = i;
    }

  return TRUE;
}

Here is the call graph for this function:

Definition at line 2043 of file elf64-mmix.c.

{
  asection *o;

  for (o = abfd->sections; o != NULL; o = o->next)
    {
      Elf_Internal_Rela *internal_relocs;
      bfd_boolean ok;

      if ((o->flags & SEC_RELOC) == 0
         || o->reloc_count == 0
         || ((info->strip == strip_all || info->strip == strip_debugger)
             && (o->flags & SEC_DEBUGGING) != 0)
         || bfd_is_abs_section (o->output_section))
       continue;

      internal_relocs
       = _bfd_elf_link_read_relocs (abfd, o, (PTR) NULL,
                                 (Elf_Internal_Rela *) NULL,
                                 info->keep_memory);
      if (internal_relocs == NULL)
       return FALSE;

      ok = mmix_elf_check_common_relocs (abfd, info, o, internal_relocs);

      if (! info->keep_memory)
       free (internal_relocs);

      if (! ok)
       return FALSE;
    }

  return TRUE;
}

Here is the call graph for this function:

static reloc_howto_type* bfd_elf64_bfd_reloc_name_lookup ( bfd *abfd  ATTRIBUTE_UNUSED,
const char *  r_name 
) [static]

Definition at line 852 of file elf64-mmix.c.

{
  unsigned int i;

  for (i = 0;
       i < sizeof (elf_mmix_howto_table) / sizeof (elf_mmix_howto_table[0]);
       i++)
    if (elf_mmix_howto_table[i].name != NULL
       && strcasecmp (elf_mmix_howto_table[i].name, r_name) == 0)
      return &elf_mmix_howto_table[i];

  return NULL;
}

Here is the call graph for this function:

static reloc_howto_type* bfd_elf64_bfd_reloc_type_lookup ( abfd  ,
bfd_reloc_code_real_type  code 
) [static]

Definition at line 834 of file elf64-mmix.c.

{
  unsigned int i;

  for (i = 0;
       i < sizeof (mmix_reloc_map) / sizeof (mmix_reloc_map[0]);
       i++)
    {
      if (mmix_reloc_map[i].bfd_reloc_val == code)
       return &elf_mmix_howto_table[mmix_reloc_map[i].elf_reloc_val];
    }

  return NULL;
}
static int bpo_reloc_request_sort_fn ( PTR  p1,
const PTR  p2 
) const [static]

Definition at line 2473 of file elf64-mmix.c.

{
  const struct bpo_reloc_request *r1 = (const struct bpo_reloc_request *) p1;
  const struct bpo_reloc_request *r2 = (const struct bpo_reloc_request *) p2;

  /* Primary function is validity; non-valid relocs sorted after valid
     ones.  */
  if (r1->valid != r2->valid)
    return r2->valid - r1->valid;

  /* Then sort on value.  Don't simplify and return just the difference of
     the values: the upper bits of the 64-bit value would be truncated on
     a host with 32-bit ints.  */
  if (r1->value != r2->value)
    return r1->value > r2->value ? 1 : -1;

  /* As a last re-sort, use the relocation number, so we get a stable
     sort.  The *addresses* aren't stable since items are swapped during
     sorting.  It depends on the qsort implementation if this actually
     happens.  */
  return r1->bpo_reloc_no > r2->bpo_reloc_no
    ? 1 : (r1->bpo_reloc_no < r2->bpo_reloc_no ? -1 : 0);
}

Here is the caller graph for this function:

Definition at line 2503 of file elf64-mmix.c.

{
  bfd *bpo_greg_owner;
  asection *bpo_gregs_section;
  struct bpo_greg_section_info *gregdata;
  unsigned int i;

  if (link_info == NULL || link_info->base_file == NULL)
    return;

  bpo_greg_owner = (bfd *) link_info->base_file;

  bpo_gregs_section
    = bfd_get_section_by_name (bpo_greg_owner,
                            MMIX_LD_ALLOCATED_REG_CONTENTS_SECTION_NAME);

  if (bpo_gregs_section == NULL)
    return;

  gregdata = mmix_elf_section_data (bpo_gregs_section)->bpo.greg;
  if (gregdata == NULL)
    return;

  if (pf == NULL)
    pf = _bfd_error_handler;

  /* These format strings are not translated.  They are for debug purposes
     only and never displayed to an end user.  Should they escape, we
     surely want them in original.  */
  (*pf) (" n_bpo_relocs: %u\n n_max_bpo_relocs: %u\n n_remain...round: %u\n\
 n_allocated_bpo_gregs: %u\n", gregdata->n_bpo_relocs,
     gregdata->n_max_bpo_relocs,
     gregdata->n_remaining_bpo_relocs_this_relaxation_round,
     gregdata->n_allocated_bpo_gregs);

  if (gregdata->reloc_request)
    for (i = 0; i < gregdata->n_max_bpo_relocs; i++)
      (*pf) ("%4u (%4u)/%4u#%u: 0x%08lx%08lx  r: %3u o: %3u\n",
            i,
            (gregdata->bpo_reloc_indexes != NULL
             ? gregdata->bpo_reloc_indexes[i] : (size_t) -1),
            gregdata->reloc_request[i].bpo_reloc_no,
            gregdata->reloc_request[i].valid,

            (unsigned long) (gregdata->reloc_request[i].value >> 32),
            (unsigned long) gregdata->reloc_request[i].value,
            gregdata->reloc_request[i].regindex,
            gregdata->reloc_request[i].offset);
}

Here is the call graph for this function:

bfd_boolean mmix_elf_add_symbol_hook ( bfd abfd,
info  ,
Elf_Internal_Sym *  sym,
namep  ,
flagsp  ,
asection **  secp,
valp   
)

Definition at line 2171 of file elf64-mmix.c.

{
  if (sym->st_shndx == SHN_REGISTER)
    {
      *secp = bfd_make_section_old_way (abfd, MMIX_REG_SECTION_NAME);
      (*secp)->flags |= SEC_LINKER_CREATED;
    }
  else if ((*namep)[0] == '_' && (*namep)[1] == '_' && (*namep)[2] == '.'
          && CONST_STRNEQ (*namep, MMIX_LOC_SECTION_START_SYMBOL_PREFIX))
    {
      /* See if we have another one.  */
      struct bfd_link_hash_entry *h = bfd_link_hash_lookup (info->hash,
                                                     *namep,
                                                     FALSE,
                                                     FALSE,
                                                     FALSE);

      if (h != NULL && h->type != bfd_link_hash_undefined)
       {
         /* 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_set_error (bfd_error_bad_value);
          return FALSE;
       }
    }

  return TRUE;
}

Here is the call graph for this function:

static bfd_boolean mmix_elf_check_common_relocs ( bfd abfd,
struct bfd_link_info info,
asection sec,
const Elf_Internal_Rela relocs 
) [static]

Definition at line 1839 of file elf64-mmix.c.

{
  bfd *bpo_greg_owner = NULL;
  asection *allocated_gregs_section = NULL;
  struct bpo_greg_section_info *gregdata = NULL;
  struct bpo_reloc_section_info *bpodata = NULL;
  const Elf_Internal_Rela *rel;
  const Elf_Internal_Rela *rel_end;

  /* We currently have to abuse this COFF-specific member, since there's
     no target-machine-dedicated member.  There's no alternative outside
     the bfd_link_info struct; we can't specialize a hash-table since
     they're different between ELF and mmo.  */
  bpo_greg_owner = (bfd *) info->base_file;

  rel_end = relocs + sec->reloc_count;
  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
            the ELF dynobj for this, since the ELF bits assume lots of
            DSO-related stuff if that member is non-NULL.  */
       case R_MMIX_BASE_PLUS_OFFSET:
         /* We don't do anything with this reloc for a relocatable link.  */
         if (info->relocatable)
           break;

         if (bpo_greg_owner == NULL)
           {
             bpo_greg_owner = abfd;
             info->base_file = (PTR) bpo_greg_owner;
           }

         if (allocated_gregs_section == NULL)
           allocated_gregs_section
             = bfd_get_section_by_name (bpo_greg_owner,
                                    MMIX_LD_ALLOCATED_REG_CONTENTS_SECTION_NAME);

         if (allocated_gregs_section == NULL)
           {
             allocated_gregs_section
              = bfd_make_section_with_flags (bpo_greg_owner,
                                          MMIX_LD_ALLOCATED_REG_CONTENTS_SECTION_NAME,
                                          (SEC_HAS_CONTENTS
                                          | SEC_IN_MEMORY
                                          | SEC_LINKER_CREATED));
             /* Setting both SEC_ALLOC and SEC_LOAD means the section is
               treated like any other section, and we'd get errors for
               address overlap with the text section.  Let's set none of
               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))
              return FALSE;

             gregdata = (struct bpo_greg_section_info *)
              bfd_zalloc (bpo_greg_owner, sizeof (struct bpo_greg_section_info));
             if (gregdata == NULL)
              return FALSE;
             mmix_elf_section_data (allocated_gregs_section)->bpo.greg
              = gregdata;
           }
         else if (gregdata == NULL)
           gregdata
             = mmix_elf_section_data (allocated_gregs_section)->bpo.greg;

         /* Get ourselves some auxiliary info for the BPO-relocs.  */
         if (bpodata == NULL)
           {
             /* No use doing a separate iteration pass to find the upper
               limit - just use the number of relocs.  */
             bpodata = (struct bpo_reloc_section_info *)
              bfd_alloc (bpo_greg_owner,
                        sizeof (struct bpo_reloc_section_info)
                        * (sec->reloc_count + 1));
             if (bpodata == NULL)
              return FALSE;
             mmix_elf_section_data (sec)->bpo.reloc = bpodata;
             bpodata->first_base_plus_offset_reloc
              = bpodata->bpo_index
              = gregdata->n_max_bpo_relocs;
             bpodata->bpo_greg_section
              = allocated_gregs_section;
             bpodata->n_bpo_relocs_this_section = 0;
           }

         bpodata->n_bpo_relocs_this_section++;
         gregdata->n_max_bpo_relocs++;

         /* We don't get another chance to set this before GC; we've not
            set up any hook that runs before GC.  */
         gregdata->n_bpo_relocs
           = gregdata->n_max_bpo_relocs;
         break;

       case R_MMIX_PUSHJ_STUBBABLE:
         mmix_elf_section_data (sec)->pjs.n_pushj_relocs++;
         break;
       }
    }

  /* Allocate per-reloc stub storage and initialize it to the max stub
     size.  */
  if (mmix_elf_section_data (sec)->pjs.n_pushj_relocs != 0)
    {
      size_t i;

      mmix_elf_section_data (sec)->pjs.stub_size
       = bfd_alloc (abfd, mmix_elf_section_data (sec)->pjs.n_pushj_relocs
                   * sizeof (mmix_elf_section_data (sec)
                            ->pjs.stub_size[0]));
      if (mmix_elf_section_data (sec)->pjs.stub_size == NULL)
       return FALSE;

      for (i = 0; i < mmix_elf_section_data (sec)->pjs.n_pushj_relocs; i++)
       mmix_elf_section_data (sec)->pjs.stub_size[i] = MAX_PUSHJ_STUB_SIZE;
    }

  return TRUE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static bfd_boolean mmix_elf_check_relocs ( bfd abfd,
struct bfd_link_info info,
asection sec,
const Elf_Internal_Rela relocs 
) [static]

Definition at line 1972 of file elf64-mmix.c.

{
  Elf_Internal_Shdr *symtab_hdr;
  struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
  const Elf_Internal_Rela *rel;
  const Elf_Internal_Rela *rel_end;

  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
  sym_hashes = elf_sym_hashes (abfd);
  sym_hashes_end = sym_hashes + symtab_hdr->sh_size/sizeof(Elf64_External_Sym);
  if (!elf_bad_symtab (abfd))
    sym_hashes_end -= symtab_hdr->sh_info;

  /* First we sort the relocs so that any register relocs come before
     expansion-relocs to the same insn.  FIXME: Not done for mmo.  */
  qsort ((PTR) relocs, sec->reloc_count, sizeof (Elf_Internal_Rela),
        mmix_elf_sort_relocs);

  /* Do the common part.  */
  if (!mmix_elf_check_common_relocs (abfd, info, sec, relocs))
    return FALSE;

  if (info->relocatable)
    return TRUE;

  rel_end = relocs + sec->reloc_count;
  for (rel = relocs; rel < rel_end; rel++)
    {
      struct elf_link_hash_entry *h;
      unsigned long r_symndx;

      r_symndx = ELF64_R_SYM (rel->r_info);
      if (r_symndx < symtab_hdr->sh_info)
        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;
       }

      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:
          if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
            return FALSE;
          break;
       }
    }

  return TRUE;
}

Here is the call graph for this function:

Definition at line 2244 of file elf64-mmix.c.

{
  /* We never output a register section, though we create one for
     temporary measures.  Check that nobody entered contents into it.  */
  asection *reg_section;

  reg_section = bfd_get_section_by_name (abfd, MMIX_REG_SECTION_NAME);

  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"));

      /* Really remove the section, if it hasn't already been done.  */
      if (!bfd_section_removed_from_list (abfd, reg_section))
       {
         bfd_section_list_remove (abfd, reg_section);
         --abfd->section_count;
       }
    }

  if (! bfd_elf_final_link (abfd, info))
    return FALSE;

  /* Since this section is marked SEC_LINKER_CREATED, it isn't output by
     the regular linker machinery.  We do it here, like other targets with
     special sections.  */
  if (info->base_file != NULL)
    {
      asection *greg_section
       = bfd_get_section_by_name ((bfd *) info->base_file,
                               MMIX_LD_ALLOCATED_REG_CONTENTS_SECTION_NAME);
      if (!bfd_set_section_contents (abfd,
                                 greg_section->output_section,
                                 greg_section->contents,
                                 (file_ptr) greg_section->output_offset,
                                 greg_section->size))
       return FALSE;
    }
  return TRUE;
}

Here is the call graph for this function:

static asection* mmix_elf_gc_mark_hook ( asection sec,
struct bfd_link_info info,
Elf_Internal_Rela rel,
struct elf_link_hash_entry h,
Elf_Internal_Sym *  sym 
) [static]

Definition at line 1757 of file elf64-mmix.c.

{
  if (h != NULL)
    switch (ELF64_R_TYPE (rel->r_info))
      {
      case R_MMIX_GNU_VTINHERIT:
      case R_MMIX_GNU_VTENTRY:
       return NULL;
      }

  return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
}

Here is the call graph for this function:

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 
) [static]

Definition at line 1780 of file elf64-mmix.c.

{
  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;
}
bfd_boolean mmix_elf_is_local_label_name ( bfd abfd,
const char *  name 
)

Definition at line 2214 of file elf64-mmix.c.

{
  const char *colpos;
  int digits;

  /* Also include the default local-label definition.  */
  if (_bfd_elf_is_local_label_name (abfd, name))
    return TRUE;

  if (*name != 'L')
    return FALSE;

  /* If there's no ":", or more than one, it's not a local symbol.  */
  colpos = strchr (name, ':');
  if (colpos == NULL || strchr (colpos + 1, ':') != NULL)
    return FALSE;

  /* Check that there are remaining characters and that they are digits.  */
  if (colpos[1] == 0)
    return FALSE;

  digits = strspn (colpos + 1, "0123456789");
  return digits != 0 && colpos[1 + digits] == 0;
}

Here is the call graph for this function:

static bfd_boolean mmix_elf_link_output_symbol_hook ( info  ,
name  ,
Elf_Internal_Sym *  sym,
asection input_sec,
 
) [static]

Definition at line 2085 of file elf64-mmix.c.

{
  if (input_sec != NULL
      && input_sec->name != NULL
      && ELF_ST_TYPE (sym->st_info) != STT_SECTION
      && strcmp (input_sec->name, MMIX_REG_CONTENTS_SECTION_NAME) == 0)
    {
      sym->st_value /= 8;
      sym->st_shndx = SHN_REGISTER;
    }

  return TRUE;
}

Here is the call graph for this function:

static bfd_boolean mmix_elf_new_section_hook ( bfd abfd,
asection sec 
) [static]

Definition at line 868 of file elf64-mmix.c.

{
  if (!sec->used_by_bfd)
    {
      struct _mmix_elf_section_data *sdata;
      bfd_size_type amt = sizeof (*sdata);

      sdata = bfd_zalloc (abfd, amt);
      if (sdata == NULL)
       return FALSE;
      sec->used_by_bfd = sdata;
    }

  return _bfd_elf_new_section_hook (abfd, sec);
}

Here is the call graph for this function:

static bfd_reloc_status_type mmix_elf_perform_relocation ( asection isec,
reloc_howto_type *  howto,
PTR  datap,
bfd_vma  addr,
bfd_vma  value 
) [static]

Definition at line 935 of file elf64-mmix.c.

{
  bfd *abfd = isec->owner;
  bfd_reloc_status_type flag = bfd_reloc_ok;
  bfd_reloc_status_type r;
  int offs = 0;
  int reg = 255;

  /* The worst case bits are all similar SETL/INCML/INCMH/INCH sequences.
     We handle the differences here and the common sequence later.  */
  switch (howto->type)
    {
    case R_MMIX_GETA:
      offs = 0;
      reg = bfd_get_8 (abfd, (bfd_byte *) datap + 1);

      /* We change to an absolute value.  */
      value += addr;
      break;

    case R_MMIX_CBRANCH:
      {
       int in1 = bfd_get_16 (abfd, (bfd_byte *) datap) << 16;

       /* Invert the condition and prediction bit, and set the offset
          to five instructions ahead.

          We *can* do better if we want to.  If the branch is found to be
          within limits, we could leave the branch as is; there'll just
          be a bunch of NOP:s after it.  But we shouldn't see this
          sequence often enough that it's worth doing it.  */

       bfd_put_32 (abfd,
                  (((in1 ^ ((PRED_INV_BIT | COND_INV_BIT) << 24)) & ~0xffff)
                   | (24/4)),
                  (bfd_byte *) datap);

       /* Put a "GO $255,$255,0" after the common sequence.  */
       bfd_put_32 (abfd,
                  ((GO_INSN_BYTE | IMM_OFFSET_BIT) << 24) | 0xffff00,
                  (bfd_byte *) datap + 20);

       /* Common sequence starts at offset 4.  */
       offs = 4;

       /* We change to an absolute value.  */
       value += addr;
      }
      break;

    case R_MMIX_PUSHJ_STUBBABLE:
      /* If the address fits, we're fine.  */
      if ((value & 3) == 0
         /* Note rightshift 0; see R_MMIX_JMP case below.  */
         && (r = bfd_check_overflow (complain_overflow_signed,
                                  howto->bitsize,
                                  0,
                                  bfd_arch_bits_per_address (abfd),
                                  value)) == bfd_reloc_ok)
       goto pcrel_mmix_reloc_fits;
      else
       {
         bfd_size_type size = isec->rawsize ? isec->rawsize : isec->size;

         /* We have the bytes at the PUSHJ insn and need to get the
            position for the stub.  There's supposed to be room allocated
            for the stub.  */
         bfd_byte *stubcontents
           = ((bfd_byte *) datap
              - (addr - (isec->output_section->vma + isec->output_offset))
              + size
              + mmix_elf_section_data (isec)->pjs.stub_offset);
         bfd_vma stubaddr;

         /* The address doesn't fit, so redirect the PUSHJ to the
            location of the stub.  */
         r = mmix_elf_perform_relocation (isec,
                                      &elf_mmix_howto_table
                                      [R_MMIX_ADDR19],
                                      datap,
                                      addr,
                                      isec->output_section->vma
                                      + isec->output_offset
                                      + size
                                      + (mmix_elf_section_data (isec)
                                         ->pjs.stub_offset)
                                      - addr);
         if (r != bfd_reloc_ok)
           return r;

         stubaddr
           = (isec->output_section->vma
              + isec->output_offset
              + size
              + mmix_elf_section_data (isec)->pjs.stub_offset);

         /* We generate a simple JMP if that suffices, else the whole 5
            insn stub.  */
         if (bfd_check_overflow (complain_overflow_signed,
                              elf_mmix_howto_table[R_MMIX_ADDR27].bitsize,
                              0,
                              bfd_arch_bits_per_address (abfd),
                              addr + value - stubaddr) == bfd_reloc_ok)
           {
             bfd_put_32 (abfd, JMP_INSN_BYTE << 24, stubcontents);
             r = mmix_elf_perform_relocation (isec,
                                          &elf_mmix_howto_table
                                          [R_MMIX_ADDR27],
                                          stubcontents,
                                          stubaddr,
                                          value + addr - stubaddr);
             mmix_elf_section_data (isec)->pjs.stub_offset += 4;

             if (size + mmix_elf_section_data (isec)->pjs.stub_offset
                > isec->size)
              abort ();

             return r;
           }
         else
           {
             /* Put a "GO $255,0" after the common sequence.  */
             bfd_put_32 (abfd,
                       ((GO_INSN_BYTE | IMM_OFFSET_BIT) << 24)
                       | 0xff00, (bfd_byte *) stubcontents + 16);

             /* Prepare for the general code to set the first part of the
               linker stub, and */
             value += addr;
             datap = stubcontents;
             mmix_elf_section_data (isec)->pjs.stub_offset
              += MAX_PUSHJ_STUB_SIZE;
           }
       }
      break;

    case R_MMIX_PUSHJ:
      {
       int inreg = bfd_get_8 (abfd, (bfd_byte *) datap + 1);

       /* Put a "PUSHGO $N,$255,0" after the common sequence.  */
       bfd_put_32 (abfd,
                  ((PUSHGO_INSN_BYTE | IMM_OFFSET_BIT) << 24)
                  | (inreg << 16)
                  | 0xff00,
                  (bfd_byte *) datap + 16);

       /* We change to an absolute value.  */
       value += addr;
      }
      break;

    case R_MMIX_JMP:
      /* This one is a little special.  If we get here on a non-relaxing
        link, and the destination is actually in range, we don't need to
        execute the nops.
        If so, we fall through to the bit-fiddling relocs.

        FIXME: bfd_check_overflow seems broken; the relocation is
        rightshifted before testing, so supply a zero rightshift.  */

      if (! ((value & 3) == 0
            && (r = bfd_check_overflow (complain_overflow_signed,
                                    howto->bitsize,
                                    0,
                                    bfd_arch_bits_per_address (abfd),
                                    value)) == bfd_reloc_ok))
       {
         /* If the relocation doesn't fit in a JMP, we let the NOP:s be
            modified below, and put a "GO $255,$255,0" after the
            address-loading sequence.  */
         bfd_put_32 (abfd,
                    ((GO_INSN_BYTE | IMM_OFFSET_BIT) << 24)
                    | 0xffff00,
                    (bfd_byte *) datap + 16);

         /* We change to an absolute value.  */
         value += addr;
         break;
       }
      /* FALLTHROUGH.  */
    case R_MMIX_ADDR19:
    case R_MMIX_ADDR27:
    pcrel_mmix_reloc_fits:
      /* These must be in range, or else we emit an error.  */
      if ((value & 3) == 0
         /* Note rightshift 0; see above.  */
         && (r = bfd_check_overflow (complain_overflow_signed,
                                  howto->bitsize,
                                  0,
                                  bfd_arch_bits_per_address (abfd),
                                  value)) == bfd_reloc_ok)
       {
         bfd_vma in1
           = bfd_get_32 (abfd, (bfd_byte *) datap);
         bfd_vma highbit;

         if ((bfd_signed_vma) value < 0)
           {
             highbit = 1 << 24;
             value += (1 << (howto->bitsize - 1));
           }
         else
           highbit = 0;

         value >>= 2;

         bfd_put_32 (abfd,
                    (in1 & howto->src_mask)
                    | highbit
                    | (value & howto->dst_mask),
                    (bfd_byte *) datap);

         return bfd_reloc_ok;
       }
      else
       return bfd_reloc_overflow;

    case R_MMIX_BASE_PLUS_OFFSET:
      {
       struct bpo_reloc_section_info *bpodata
         = mmix_elf_section_data (isec)->bpo.reloc;
       asection *bpo_greg_section
         = bpodata->bpo_greg_section;
       struct bpo_greg_section_info *gregdata
         = mmix_elf_section_data (bpo_greg_section)->bpo.greg;
       size_t bpo_index
         = gregdata->bpo_reloc_indexes[bpodata->bpo_index++];

       /* A consistency check: The value we now have in "relocation" must
          be the same as the value we stored for that relocation.  It
          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_set_error (bfd_error_bad_value);
           return bfd_reloc_overflow;
         }

       /* Then store the register number and offset for that register
          into datap and datap + 1 respectively.  */
       bfd_put_8 (abfd,
                 gregdata->reloc_request[bpo_index].regindex
                 + bpo_greg_section->output_section->vma / 8,
                 datap);
       bfd_put_8 (abfd,
                 gregdata->reloc_request[bpo_index].offset,
                 ((unsigned char *) datap) + 1);
       return bfd_reloc_ok;
      }

    case R_MMIX_REG_OR_BYTE:
    case R_MMIX_REG:
      if (value > 255)
       return bfd_reloc_overflow;
      bfd_put_8 (abfd, value, datap);
      return bfd_reloc_ok;

    default:
      BAD_CASE (howto->type);
    }

  /* This code adds the common SETL/INCML/INCMH/INCH worst-case
     sequence.  */

  /* Lowest two bits must be 0.  We return bfd_reloc_overflow for
     everything that looks strange.  */
  if (value & 3)
    flag = bfd_reloc_overflow;

  bfd_put_32 (abfd,
             (SETL_INSN_BYTE << 24) | (value & 0xffff) | (reg << 16),
             (bfd_byte *) datap + offs);
  bfd_put_32 (abfd,
             (INCML_INSN_BYTE << 24) | ((value >> 16) & 0xffff) | (reg << 16),
             (bfd_byte *) datap + offs + 4);
  bfd_put_32 (abfd,
             (INCMH_INSN_BYTE << 24) | ((value >> 32) & 0xffff) | (reg << 16),
             (bfd_byte *) datap + offs + 8);
  bfd_put_32 (abfd,
             (INCH_INSN_BYTE << 24) | ((value >> 48) & 0xffff) | (reg << 16),
             (bfd_byte *) datap + offs + 12);

  return flag;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static bfd_boolean mmix_elf_relax_section ( bfd abfd,
asection sec,
struct bfd_link_info link_info,
bfd_boolean again 
) [static]

Definition at line 2566 of file elf64-mmix.c.

{
  Elf_Internal_Shdr *symtab_hdr;
  Elf_Internal_Rela *internal_relocs;
  Elf_Internal_Rela *irel, *irelend;
  asection *bpo_gregs_section = NULL;
  struct bpo_greg_section_info *gregdata;
  struct bpo_reloc_section_info *bpodata
    = mmix_elf_section_data (sec)->bpo.reloc;
  /* The initialization is to quiet compiler warnings.  The value is to
     spot a missing actual initialization.  */
  size_t bpono = (size_t) -1;
  size_t pjsno = 0;
  bfd *bpo_greg_owner;
  Elf_Internal_Sym *isymbuf = NULL;
  bfd_size_type size = sec->rawsize ? sec->rawsize : sec->size;

  mmix_elf_section_data (sec)->pjs.stubs_size_sum = 0;

  /* Assume nothing changes.  */
  *again = FALSE;

  /* We don't have to do anything if this section does not have relocs, or
     if this is not a code section.  */
  if ((sec->flags & SEC_RELOC) == 0
      || sec->reloc_count == 0
      || (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.  */
      || (bpodata == NULL
         && mmix_elf_section_data (sec)->pjs.n_pushj_relocs == 0))
    return TRUE;

  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;

  bpo_greg_owner = (bfd *) link_info->base_file;

  if (bpodata != NULL)
    {
      bpo_gregs_section = bpodata->bpo_greg_section;
      gregdata = mmix_elf_section_data (bpo_gregs_section)->bpo.greg;
      bpono = bpodata->first_base_plus_offset_reloc;
    }
  else
    gregdata = NULL;

  /* Get a copy of the native relocations.  */
  internal_relocs
    = _bfd_elf_link_read_relocs (abfd, sec, (PTR) NULL,
                             (Elf_Internal_Rela *) NULL,
                             link_info->keep_memory);
  if (internal_relocs == NULL)
    goto error_return;

  /* Walk through them looking for relaxing opportunities.  */
  irelend = internal_relocs + sec->reloc_count;
  for (irel = internal_relocs; irel < irelend; irel++)
    {
      bfd_vma symval;
      struct elf_link_hash_entry *h = NULL;

      /* We only process two relocs.  */
      if (ELF64_R_TYPE (irel->r_info) != (int) R_MMIX_BASE_PLUS_OFFSET
         && ELF64_R_TYPE (irel->r_info) != (int) R_MMIX_PUSHJ_STUBBABLE)
       continue;

      /* We process relocs in a distinctly different way when this is a
        relocatable link (for one, we don't look at symbols), so we avoid
        mixing its code with that for the "normal" relaxation.  */
      if (link_info->relocatable)
       {
         /* The only transformation in a relocatable link is to generate
            a full stub at the location of the stub calculated for the
            input section, if the relocated stub location, the end of the
            output section plus earlier stubs, cannot be reached.  Thus
            relocatable linking can only lead to worse code, but it still
            works.  */
         if (ELF64_R_TYPE (irel->r_info) == R_MMIX_PUSHJ_STUBBABLE)
           {
             /* If we can reach the end of the output-section and beyond
               any current stubs, then we don't need a stub for this
               reloc.  The relaxed order of output stub allocation may
               not exactly match the straightforward order, so we always
               assume presence of output stubs, which will allow
               relaxation only on relocations indifferent to the
               presence of output stub allocations for other relocations
               and thus the order of output stub allocation.  */
             if (bfd_check_overflow (complain_overflow_signed,
                                  19,
                                  0,
                                  bfd_arch_bits_per_address (abfd),
                                  /* Output-stub location.  */
                                  sec->output_section->rawsize
                                  + (mmix_elf_section_data (sec
                                                        ->output_section)
                                    ->pjs.stubs_size_sum)
                                  /* Location of this PUSHJ reloc.  */
                                  - (sec->output_offset + irel->r_offset)
                                  /* Don't count *this* stub twice.  */
                                  - (mmix_elf_section_data (sec)
                                    ->pjs.stub_size[pjsno]
                                    + MAX_PUSHJ_STUB_SIZE))
                == bfd_reloc_ok)
              mmix_elf_section_data (sec)->pjs.stub_size[pjsno] = 0;

             mmix_elf_section_data (sec)->pjs.stubs_size_sum
              += mmix_elf_section_data (sec)->pjs.stub_size[pjsno];

             pjsno++;
           }

         continue;
       }

      /* Get the value of the symbol referred to by the reloc.  */
      if (ELF64_R_SYM (irel->r_info) < symtab_hdr->sh_info)
       {
         /* A local symbol.  */
         Elf_Internal_Sym *isym;
         asection *sym_sec;

         /* Read this BFD's local symbols if we haven't already.  */
         if (isymbuf == NULL)
           {
             isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
             if (isymbuf == NULL)
              isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
                                          symtab_hdr->sh_info, 0,
                                          NULL, NULL, NULL);
             if (isymbuf == 0)
              goto error_return;
           }

         isym = isymbuf + ELF64_R_SYM (irel->r_info);
         if (isym->st_shndx == SHN_UNDEF)
           sym_sec = bfd_und_section_ptr;
         else if (isym->st_shndx == SHN_ABS)
           sym_sec = bfd_abs_section_ptr;
         else if (isym->st_shndx == SHN_COMMON)
           sym_sec = bfd_com_section_ptr;
         else
           sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
         symval = (isym->st_value
                  + sym_sec->output_section->vma
                  + sym_sec->output_offset);
       }
      else
       {
         unsigned long indx;

         /* An external symbol.  */
         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)
           {
             /* This appears to be a reference to an undefined symbol.  Just
               ignore it--it will be caught by the regular reloc processing.
               We need to keep BPO reloc accounting consistent, though
               else we'll abort instead of emitting an error message.  */
             if (ELF64_R_TYPE (irel->r_info) == R_MMIX_BASE_PLUS_OFFSET
                && gregdata != NULL)
              {
                gregdata->n_remaining_bpo_relocs_this_relaxation_round--;
                bpono++;
              }
             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_vma value = symval + irel->r_addend;
         bfd_vma dot
           = (sec->output_section->vma
              + sec->output_offset
              + irel->r_offset);
         bfd_vma stubaddr
           = (sec->output_section->vma
              + sec->output_offset
              + size
              + mmix_elf_section_data (sec)->pjs.stubs_size_sum);

         if ((value & 3) == 0
             && bfd_check_overflow (complain_overflow_signed,
                                 19,
                                 0,
                                 bfd_arch_bits_per_address (abfd),
                                 value - dot
                                 - (value > dot
                                   ? mmix_elf_section_data (sec)
                                   ->pjs.stub_size[pjsno]
                                   : 0))
             == bfd_reloc_ok)
           /* If the reloc fits, no stub is needed.  */
           mmix_elf_section_data (sec)->pjs.stub_size[pjsno] = 0;
         else
           /* Maybe we can get away with just a JMP insn?  */
           if ((value & 3) == 0
              && bfd_check_overflow (complain_overflow_signed,
                                   27,
                                   0,
                                   bfd_arch_bits_per_address (abfd),
                                   value - stubaddr
                                   - (value > dot
                                     ? mmix_elf_section_data (sec)
                                     ->pjs.stub_size[pjsno] - 4
                                     : 0))
              == bfd_reloc_ok)
             /* Yep, account for a stub consisting of a single JMP insn.  */
             mmix_elf_section_data (sec)->pjs.stub_size[pjsno] = 4;
         else
           /* Nope, go for the full insn stub.  It doesn't seem useful to
              emit the intermediate sizes; those will only be useful for
              a >64M program assuming contiguous code.  */
           mmix_elf_section_data (sec)->pjs.stub_size[pjsno]
             = MAX_PUSHJ_STUB_SIZE;

         mmix_elf_section_data (sec)->pjs.stubs_size_sum
           += mmix_elf_section_data (sec)->pjs.stub_size[pjsno];
         pjsno++;
         continue;
       }

      /* We're looking at a R_MMIX_BASE_PLUS_OFFSET reloc.  */

      gregdata->reloc_request[gregdata->bpo_reloc_indexes[bpono]].value
       = symval + irel->r_addend;
      gregdata->reloc_request[gregdata->bpo_reloc_indexes[bpono++]].valid = TRUE;
      gregdata->n_remaining_bpo_relocs_this_relaxation_round--;
    }

  /* Check if that was the last BPO-reloc.  If so, sort the values and
     calculate how many registers we need to cover them.  Set the size of
     the linker gregs, and if the number of registers changed, indicate
     that we need to relax some more because we have more work to do.  */
  if (gregdata != NULL
      && gregdata->n_remaining_bpo_relocs_this_relaxation_round == 0)
    {
      size_t i;
      bfd_vma prev_base;
      size_t regindex;

      /* First, reset the remaining relocs for the next round.  */
      gregdata->n_remaining_bpo_relocs_this_relaxation_round
       = gregdata->n_bpo_relocs;

      qsort ((PTR) gregdata->reloc_request,
            gregdata->n_max_bpo_relocs,
            sizeof (struct bpo_reloc_request),
            bpo_reloc_request_sort_fn);

      /* Recalculate indexes.  When we find a change (however unlikely
        after the initial iteration), we know we need to relax again,
        since items in the GREG-array are sorted by increasing value and
        stored in the relaxation phase.  */
      for (i = 0; i < gregdata->n_max_bpo_relocs; i++)
       if (gregdata->bpo_reloc_indexes[gregdata->reloc_request[i].bpo_reloc_no]
           != i)
         {
           gregdata->bpo_reloc_indexes[gregdata->reloc_request[i].bpo_reloc_no]
             = i;
           *again = TRUE;
         }

      /* Allocate register numbers (indexing from 0).  Stop at the first
        non-valid reloc.  */
      for (i = 0, regindex = 0, prev_base = gregdata->reloc_request[0].value;
          i < gregdata->n_bpo_relocs;
          i++)
       {
         if (gregdata->reloc_request[i].value > prev_base + 255)
           {
             regindex++;
             prev_base = gregdata->reloc_request[i].value;
           }
         gregdata->reloc_request[i].regindex = regindex;
         gregdata->reloc_request[i].offset
           = gregdata->reloc_request[i].value - prev_base;
       }

      /* If it's not the same as the last time, we need to relax again,
        because the size of the section has changed.  I'm not sure we
        actually need to do any adjustments since the shrinking happens
        at the start of this section, but better safe than sorry.  */
      if (gregdata->n_allocated_bpo_gregs != regindex + 1)
       {
         gregdata->n_allocated_bpo_gregs = regindex + 1;
         *again = TRUE;
       }

      bpo_gregs_section->size = (regindex + 1) * 8;
    }

  if (isymbuf != NULL && (unsigned char *) isymbuf != symtab_hdr->contents)
    {
      if (! link_info->keep_memory)
       free (isymbuf);
      else
       {
         /* Cache the symbols for elf_link_input_bfd.  */
         symtab_hdr->contents = (unsigned char *) isymbuf;
       }
    }

  if (internal_relocs != NULL
      && elf_section_data (sec)->relocs != internal_relocs)
    free (internal_relocs);

  if (sec->size < size + mmix_elf_section_data (sec)->pjs.stubs_size_sum)
    abort ();

  if (sec->size > size + mmix_elf_section_data (sec)->pjs.stubs_size_sum)
    {
      sec->size = size + mmix_elf_section_data (sec)->pjs.stubs_size_sum;
      *again = TRUE;
    }

  return TRUE;

 error_return:
  if (isymbuf != NULL && (unsigned char *) isymbuf != symtab_hdr->contents)
    free (isymbuf);
  if (internal_relocs != NULL
      && elf_section_data (sec)->relocs != internal_relocs)
    free (internal_relocs);
  return FALSE;
}

Here is the call graph for this function:

static bfd_reloc_status_type mmix_elf_reloc ( bfd abfd,
arelent reloc_entry,
asymbol symbol,
PTR  data,
asection input_section,
bfd output_bfd,
error_message   
) [static]

Definition at line 1253 of file elf64-mmix.c.

{
  bfd_vma relocation;
  bfd_reloc_status_type r;
  asection *reloc_target_output_section;
  bfd_reloc_status_type flag = bfd_reloc_ok;
  bfd_vma output_base = 0;
  bfd_vma addr;

  r = bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
                          input_section, output_bfd, error_message);

  /* If that was all that was needed (i.e. this isn't a final link, only
     some segment adjustments), we're done.  */
  if (r != bfd_reloc_continue)
    return r;

  if (bfd_is_und_section (symbol->section)
      && (symbol->flags & BSF_WEAK) == 0
      && output_bfd == (bfd *) NULL)
    return bfd_reloc_undefined;

  /* Is the address of the relocation really within the section?  */
  if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
    return bfd_reloc_outofrange;

  /* Work out which section the relocation is targeted at and the
     initial relocation command value.  */

  /* Get symbol value.  (Common symbols are special.)  */
  if (bfd_is_com_section (symbol->section))
    relocation = 0;
  else
    relocation = symbol->value;

  reloc_target_output_section = bfd_get_output_section (symbol);

  /* Here the variable relocation holds the final address of the symbol we
     are relocating against, plus any addend.  */
  if (output_bfd)
    output_base = 0;
  else
    output_base = reloc_target_output_section->vma;

  relocation += output_base + symbol->section->output_offset;

  /* Get position of relocation.  */
  addr = (reloc_entry->address + input_section->output_section->vma
         + input_section->output_offset);
  if (output_bfd != (bfd *) NULL)
    {
      /* Add in supplied addend.  */
      relocation += reloc_entry->addend;

      /* This is a partial relocation, and we want to apply the
        relocation to the reloc entry rather than the raw data.
        Modify the reloc inplace to reflect what we now know.  */
      reloc_entry->addend = relocation;
      reloc_entry->address += input_section->output_offset;
      return flag;
    }

  return mmix_final_link_relocate (reloc_entry->howto, input_section,
                               data, reloc_entry->address,
                               reloc_entry->addend, relocation,
                               bfd_asymbol_name (symbol),
                               reloc_target_output_section);
}

Here is the call graph for this function:

static bfd_boolean mmix_elf_relocate_section ( output_bfd  ,
struct bfd_link_info info,
bfd input_bfd,
asection input_section,
bfd_byte contents,
Elf_Internal_Rela relocs,
Elf_Internal_Sym *  local_syms,
asection **  local_sections 
) [static]

Definition at line 1334 of file elf64-mmix.c.

{
  Elf_Internal_Shdr *symtab_hdr;
  struct elf_link_hash_entry **sym_hashes;
  Elf_Internal_Rela *rel;
  Elf_Internal_Rela *relend;
  bfd_size_type size;
  size_t pjsno = 0;

  size = input_section->rawsize ? input_section->rawsize : input_section->size;
  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
  sym_hashes = elf_sym_hashes (input_bfd);
  relend = relocs + input_section->reloc_count;

  /* Zero the stub area before we start.  */
  if (input_section->rawsize != 0
      && input_section->size > input_section->rawsize)
    memset (contents + input_section->rawsize, 0,
           input_section->size - input_section->rawsize);

  for (rel = relocs; rel < relend; rel ++)
    {
      reloc_howto_type *howto;
      unsigned long r_symndx;
      Elf_Internal_Sym *sym;
      asection *sec;
      struct elf_link_hash_entry *h;
      bfd_vma relocation;
      bfd_reloc_status_type r;
      const char *name = NULL;
      int r_type;
      bfd_boolean undefined_signalled = FALSE;

      r_type = ELF64_R_TYPE (rel->r_info);

      if (r_type == R_MMIX_GNU_VTINHERIT
         || r_type == R_MMIX_GNU_VTENTRY)
       continue;

      r_symndx = ELF64_R_SYM (rel->r_info);

      howto = elf_mmix_howto_table + ELF64_R_TYPE (rel->r_info);
      h = NULL;
      sym = NULL;
      sec = NULL;

      if (r_symndx < symtab_hdr->sh_info)
       {
         sym = local_syms + r_symndx;
         sec = local_sections [r_symndx];
         relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);

         name = bfd_elf_string_from_elf_section (input_bfd,
                                            symtab_hdr->sh_link,
                                            sym->st_name);
         if (name == NULL)
           name = bfd_section_name (input_bfd, sec);
       }
      else
       {
         bfd_boolean unresolved_reloc;

         RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
                               r_symndx, symtab_hdr, sym_hashes,
                               h, sec, relocation,
                               unresolved_reloc, undefined_signalled);
         name = h->root.root.string;
       }

      if (sec != NULL && elf_discarded_section (sec))
       {
         /* For relocs against symbols from removed linkonce sections,
            or sections discarded by a linker script, we just want the
            section contents zeroed.  Avoid any special processing.  */
         _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
         rel->r_info = 0;
         rel->r_addend = 0;
         continue;
       }

      if (info->relocatable)
       {
         /* This is a relocatable link.  For most relocs we don't have to
            change anything, unless the reloc is against a section
            symbol, in which case we have to adjust according to where
            the section symbol winds up in the output section.  */
         if (sym != NULL && ELF_ST_TYPE (sym->st_info) == STT_SECTION)
           rel->r_addend += sec->output_offset;

         /* For PUSHJ stub relocs however, we may need to change the
            reloc and the section contents, if the reloc doesn't reach
            beyond the end of the output section and previous stubs.
            Then we change the section contents to be a PUSHJ to the end
            of the input section plus stubs (we can do that without using
            a reloc), and then we change the reloc to be a R_MMIX_PUSHJ
            at the stub location.  */
         if (r_type == R_MMIX_PUSHJ_STUBBABLE)
           {
             /* We've already checked whether we need a stub; use that
               knowledge.  */
             if (mmix_elf_section_data (input_section)->pjs.stub_size[pjsno]
                != 0)
              {
                Elf_Internal_Rela relcpy;

                if (mmix_elf_section_data (input_section)
                    ->pjs.stub_size[pjsno] != MAX_PUSHJ_STUB_SIZE)
                  abort ();

                /* There's already a PUSHJ insn there, so just fill in
                   the offset bits to the stub.  */
                if (mmix_final_link_relocate (elf_mmix_howto_table
                                          + R_MMIX_ADDR19,
                                          input_section,
                                          contents,
                                          rel->r_offset,
                                          0,
                                          input_section
                                          ->output_section->vma
                                          + input_section->output_offset
                                          + size
                                          + mmix_elf_section_data (input_section)
                                          ->pjs.stub_offset,
                                          NULL, NULL) != bfd_reloc_ok)
                  return FALSE;

                /* Put a JMP insn at the stub; it goes with the
                   R_MMIX_JMP reloc.  */
                bfd_put_32 (output_bfd, JMP_INSN_BYTE << 24,
                           contents
                           + size
                           + mmix_elf_section_data (input_section)
                           ->pjs.stub_offset);

                /* Change the reloc to be at the stub, and to a full
                   R_MMIX_JMP reloc.  */
                rel->r_info = ELF64_R_INFO (r_symndx, R_MMIX_JMP);
                rel->r_offset
                  = (size
                     + mmix_elf_section_data (input_section)
                     ->pjs.stub_offset);

                mmix_elf_section_data (input_section)->pjs.stub_offset
                  += MAX_PUSHJ_STUB_SIZE;

                /* Shift this reloc to the end of the relocs to maintain
                   the r_offset sorted reloc order.  */
                relcpy = *rel;
                memmove (rel, rel + 1, (char *) relend - (char *) rel);
                relend[-1] = relcpy;

                /* Back up one reloc, or else we'd skip the next reloc
                 in turn.  */
                rel--;
              }

             pjsno++;
           }
         continue;
       }

      r = mmix_final_link_relocate (howto, input_section,
                                contents, rel->r_offset,
                                rel->r_addend, relocation, name, sec);

      if (r != bfd_reloc_ok)
       {
         bfd_boolean check_ok = TRUE;
         const char * msg = (const char *) NULL;

         switch (r)
           {
           case bfd_reloc_overflow:
             check_ok = info->callbacks->reloc_overflow
              (info, (h ? &h->root : NULL), name, howto->name,
               (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
             break;

           case bfd_reloc_undefined:
             /* We may have sent this message above.  */
             if (! undefined_signalled)
              check_ok = info->callbacks->undefined_symbol
                (info, name, input_bfd, input_section, rel->r_offset,
                 TRUE);
             undefined_signalled = TRUE;
             break;

           case bfd_reloc_outofrange:
             msg = _("internal error: out of range error");
             break;

           case bfd_reloc_notsupported:
             msg = _("internal error: unsupported relocation error");
             break;

           case bfd_reloc_dangerous:
             msg = _("internal error: dangerous relocation");
             break;

           default:
             msg = _("internal error: unknown error");
             break;
           }

         if (msg)
           check_ok = info->callbacks->warning
             (info, msg, name, input_bfd, input_section, rel->r_offset);

         if (! check_ok)
           return FALSE;
       }
    }

  return TRUE;
}

Here is the call graph for this function:

static bfd_boolean mmix_elf_section_from_bfd_section ( abfd  ,
asection sec,
int retval 
) [static]

Definition at line 2150 of file elf64-mmix.c.

{
  if (strcmp (bfd_get_section_name (abfd, sec), MMIX_REG_SECTION_NAME) == 0)
    *retval = SHN_REGISTER;
  else
    return FALSE;

  return TRUE;
}

Here is the call graph for this function:

static int mmix_elf_sort_relocs ( PTR  p1,
const PTR  p2 
) const [static]

Definition at line 1804 of file elf64-mmix.c.

{
  const Elf_Internal_Rela *r1 = (const Elf_Internal_Rela *) p1;
  const Elf_Internal_Rela *r2 = (const Elf_Internal_Rela *) p2;
  int r1_is_reg, r2_is_reg;

  /* Sort primarily on r_offset & ~3, so relocs are done to consecutive
     insns.  */
  if ((r1->r_offset & ~(bfd_vma) 3) > (r2->r_offset & ~(bfd_vma) 3))
    return 1;
  else if ((r1->r_offset & ~(bfd_vma) 3) < (r2->r_offset & ~(bfd_vma) 3))
    return -1;

  r1_is_reg
    = (ELF64_R_TYPE (r1->r_info) == R_MMIX_REG_OR_BYTE
       || ELF64_R_TYPE (r1->r_info) == R_MMIX_REG);
  r2_is_reg
    = (ELF64_R_TYPE (r2->r_info) == R_MMIX_REG_OR_BYTE
       || ELF64_R_TYPE (r2->r_info) == R_MMIX_REG);
  if (r1_is_reg != r2_is_reg)
    return r2_is_reg - r1_is_reg;

  /* Neither or both are register relocs.  Then sort on full offset.  */
  if (r1->r_offset > r2->r_offset)
    return 1;
  else if (r1->r_offset < r2->r_offset)
    return -1;
  return 0;
}

Here is the caller graph for this function:

void mmix_elf_symbol_processing ( abfd  ,
asymbol asym 
)
static bfd_reloc_status_type mmix_final_link_relocate ( reloc_howto_type *  howto,
asection input_section,
bfd_byte contents,
bfd_vma  r_offset,
bfd_signed_vma  r_addend,
bfd_vma  relocation,
const char *  symname,
asection symsec 
) [static]

Definition at line 1563 of file elf64-mmix.c.

{
  bfd_reloc_status_type r = bfd_reloc_ok;
  bfd_vma addr
    = (input_section->output_section->vma
       + input_section->output_offset
       + r_offset);
  bfd_signed_vma srel
    = (bfd_signed_vma) relocation + r_addend;

  switch (howto->type)
    {
      /* All these are PC-relative.  */
    case R_MMIX_PUSHJ_STUBBABLE:
    case R_MMIX_PUSHJ:
    case R_MMIX_CBRANCH:
    case R_MMIX_ADDR19:
    case R_MMIX_GETA:
    case R_MMIX_ADDR27:
    case R_MMIX_JMP:
      contents += r_offset;

      srel -= (input_section->output_section->vma
              + input_section->output_offset
              + r_offset);

      r = mmix_elf_perform_relocation (input_section, howto, contents,
                                   addr, srel);
      break;

    case R_MMIX_BASE_PLUS_OFFSET:
      if (symsec == NULL)
       return bfd_reloc_undefined;

      /* Check that we're not relocating against a register symbol.  */
      if (strcmp (bfd_get_section_name (symsec->owner, symsec),
                MMIX_REG_CONTENTS_SECTION_NAME) == 0
         || strcmp (bfd_get_section_name (symsec->owner, 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));
         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));
         return bfd_reloc_overflow;
       }
      goto do_mmix_reloc;

    case R_MMIX_REG_OR_BYTE:
    case R_MMIX_REG:
      /* For now, we handle these alike.  They must refer to an register
        symbol, which is either relative to the register section and in
        the range 0..255, or is in the register contents section with vma
        regno * 8.  */

      /* FIXME: A better way to check for reg contents section?
        FIXME: Postpone section->scaling to mmix_elf_perform_relocation? */
      if (symsec == NULL)
       return bfd_reloc_undefined;

      if (strcmp (bfd_get_section_name (symsec->owner, symsec),
                MMIX_REG_CONTENTS_SECTION_NAME) == 0)
       {
         if ((srel & 7) != 0 || srel < 32*8 || srel > 255*8)
           {
             /* The bfd_reloc_outofrange return value, though intuitively
               a better value, will not get us an error.  */
             return bfd_reloc_overflow;
           }
         srel /= 8;
       }
      else if (strcmp (bfd_get_section_name (symsec->owner, symsec),
                     MMIX_REG_SECTION_NAME) == 0)
       {
         if (srel < 0 || srel > 255)
           /* The bfd_reloc_outofrange return value, though intuitively a
              better value, will not get us an error.  */
           return bfd_reloc_overflow;
       }
      else
       {
         /* 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));
         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));

         /* The bfd_reloc_outofrange return value, though intuitively a
            better value, will not get us an error.  */
         return bfd_reloc_overflow;
       }
    do_mmix_reloc:
      contents += r_offset;
      r = mmix_elf_perform_relocation (input_section, howto, contents,
                                   addr, srel);
      break;

    case R_MMIX_LOCAL:
      /* This isn't a real relocation, it's just an assertion that the
        final relocation value corresponds to a local register.  We
        ignore the actual relocation; nothing is changed.  */
      {
       asection *regsec
         = bfd_get_section_by_name (input_section->output_section->owner,
                                 MMIX_REG_CONTENTS_SECTION_NAME);
       bfd_vma first_global;

       /* Check that this is an absolute value, or a reference to the
          register contents section or the register (symbol) section.
          Absolute numbers can get here as undefined section.  Undefined
          symbols are signalled elsewhere, so there's no conflict in us
          accidentally handling it.  */
       if (!bfd_is_abs_section (symsec)
           && !bfd_is_und_section (symsec)
           && strcmp (bfd_get_section_name (symsec->owner, symsec),
                     MMIX_REG_CONTENTS_SECTION_NAME) != 0
           && strcmp (bfd_get_section_name (symsec->owner, 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));

         return bfd_reloc_overflow;
       }

      /* If we don't have a register contents section, then $255 is the
        first global register.  */
      if (regsec == NULL)
       first_global = 255;
      else
       {
         first_global = bfd_get_section_vma (abfd, regsec) / 8;
         if (strcmp (bfd_get_section_name (symsec->owner, symsec),
                    MMIX_REG_CONTENTS_SECTION_NAME) == 0)
           {
             if ((srel & 7) != 0 || srel < 32*8 || srel > 255*8)
              /* The bfd_reloc_outofrange return value, though
                 intuitively a better value, will not get us an error.  */
              return bfd_reloc_overflow;
             srel /= 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);

           return bfd_reloc_overflow;
         }
      }
      r = bfd_reloc_ok;
      break;

    default:
      r = _bfd_final_link_relocate (howto, input_section->owner, input_section,
                                contents, r_offset,
                                relocation, r_addend);
    }

  return r;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void mmix_info_to_howto_rela ( abfd  ,
arelent cache_ptr,
Elf_Internal_Rela dst 
) [static]

Definition at line 1236 of file elf64-mmix.c.

{
  unsigned int r_type;

  r_type = ELF64_R_TYPE (dst->r_info);
  BFD_ASSERT (r_type < (unsigned int) R_MMIX_max);
  cache_ptr->howto = &elf_mmix_howto_table[r_type];
}
static void mmix_set_relaxable_size ( abfd  ,
asection sec,
void *  ptr 
) [static]

Definition at line 2293 of file elf64-mmix.c.

{
  struct bfd_link_info *info = ptr;

  /* Make sure we only do this for section where we know we want this,
     otherwise we might end up resetting the size of COMMONs.  */
  if (mmix_elf_section_data (sec)->pjs.n_pushj_relocs == 0)
    return;

  sec->rawsize = sec->size;
  sec->size += (mmix_elf_section_data (sec)->pjs.n_pushj_relocs
              * MAX_PUSHJ_STUB_SIZE);

  /* For use in relocatable link, we start with a max stubs size.  See
     mmix_elf_relax_section.  */
  if (info->relocatable && sec->output_section)
    mmix_elf_section_data (sec->output_section)->pjs.stubs_size_sum
      += (mmix_elf_section_data (sec)->pjs.n_pushj_relocs
         * MAX_PUSHJ_STUB_SIZE);
}

Here is the caller graph for this function:

static bfd_reloc_status_type mmix_elf_reloc PARAMS ( (bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)  ) [static]
static reloc_howto_type* bfd_elf64_bfd_reloc_type_lookup PARAMS ( (bfd *, bfd_reloc_code_real_type ) [static]
static void mmix_info_to_howto_rela PARAMS ( (bfd *, arelent *, Elf_Internal_Rela *)  ) [static]
static int mmix_elf_sort_relocs PARAMS ( (const PTR, const PTR ) [static]
static bfd_boolean mmix_elf_relocate_section PARAMS ( (bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, Elf_Internal_Rela *, Elf_Internal_Sym *, asection **)  ) [static]
static bfd_reloc_status_type mmix_final_link_relocate PARAMS ( (reloc_howto_type *, asection *, bfd_byte *, bfd_vma, bfd_signed_vma, bfd_vma, const char *, asection *)  ) [static]
static bfd_reloc_status_type mmix_elf_perform_relocation PARAMS ( (asection *, reloc_howto_type *, PTR, bfd_vma, bfd_vma ) [static]
static bfd_boolean mmix_elf_add_symbol_hook PARAMS ( (bfd *, struct bfd_link_info *, Elf_Internal_Sym *, const char **, flagword *, asection **, bfd_vma *)  ) [static]
static bfd_boolean mmix_elf_is_local_label_name PARAMS ( (bfd *, const char *)  ) [static]
static bfd_boolean mmix_elf_relax_section PARAMS ( (bfd *abfd, asection *sec, struct bfd_link_info *link_info, bfd_boolean *again)  ) [static]
static void mmix_set_relaxable_size PARAMS ( (bfd *, asection *, void *)  ) [static]

Variable Documentation

reloc_howto_type elf_mmix_howto_table[] [static]

Definition at line 228 of file elf64-mmix.c.

Definition at line 2108 of file elf64-mmix.c.

Definition at line 2109 of file elf64-mmix.c.

Definition at line 2110 of file elf64-mmix.c.

struct mmix_reloc_map[] [static]
Initial value:
  {
    {BFD_RELOC_NONE, R_MMIX_NONE},
    {BFD_RELOC_8, R_MMIX_8},
    {BFD_RELOC_16, R_MMIX_16},
    {BFD_RELOC_24, R_MMIX_24},
    {BFD_RELOC_32, R_MMIX_32},
    {BFD_RELOC_64, R_MMIX_64},
    {BFD_RELOC_8_PCREL, R_MMIX_PC_8},
    {BFD_RELOC_16_PCREL, R_MMIX_PC_16},
    {BFD_RELOC_24_PCREL, R_MMIX_PC_24},
    {BFD_RELOC_32_PCREL, R_MMIX_PC_32},
    {BFD_RELOC_64_PCREL, R_MMIX_PC_64},
    {BFD_RELOC_VTABLE_INHERIT, R_MMIX_GNU_VTINHERIT},
    {BFD_RELOC_VTABLE_ENTRY, R_MMIX_GNU_VTENTRY},
    {BFD_RELOC_MMIX_GETA, R_MMIX_GETA},
    {BFD_RELOC_MMIX_CBRANCH, R_MMIX_CBRANCH},
    {BFD_RELOC_MMIX_PUSHJ, R_MMIX_PUSHJ},
    {BFD_RELOC_MMIX_JMP, R_MMIX_JMP},
    {BFD_RELOC_MMIX_ADDR19, R_MMIX_ADDR19},
    {BFD_RELOC_MMIX_ADDR27, R_MMIX_ADDR27},
    {BFD_RELOC_MMIX_REG_OR_BYTE, R_MMIX_REG_OR_BYTE},
    {BFD_RELOC_MMIX_REG, R_MMIX_REG},
    {BFD_RELOC_MMIX_BASE_PLUS_OFFSET, R_MMIX_BASE_PLUS_OFFSET},
    {BFD_RELOC_MMIX_LOCAL, R_MMIX_LOCAL},
    {BFD_RELOC_MMIX_PUSHJ_STUBBABLE, R_MMIX_PUSHJ_STUBBABLE}
  }

Definition at line 805 of file elf64-mmix.c.