OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [gdb-7.1/] [bfd/] [elf32-score.c] - Diff between revs 834 and 842

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 834 Rev 842
/* 32-bit ELF support for S+core.
/* 32-bit ELF support for S+core.
   Copyright 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
   Copyright 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
   Contributed by
   Contributed by
   Brain.lin (brain.lin@sunplusct.com)
   Brain.lin (brain.lin@sunplusct.com)
   Mei Ligang (ligang@sunnorth.com.cn)
   Mei Ligang (ligang@sunnorth.com.cn)
   Pei-Lin Tsai (pltsai@sunplus.com)
   Pei-Lin Tsai (pltsai@sunplus.com)
 
 
   This file is part of BFD, the Binary File Descriptor library.
   This file is part of BFD, the Binary File Descriptor library.
 
 
   This program is free software; you can redistribute it and/or modify
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.
   (at your option) any later version.
 
 
   This program is distributed in the hope that it will be useful,
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   GNU General Public License for more details.
 
 
   You should have received a copy of the GNU General Public License
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
   MA 02110-1301, USA.  */
   MA 02110-1301, USA.  */
 
 
#include "sysdep.h"
#include "sysdep.h"
#include "bfd.h"
#include "bfd.h"
#include "libbfd.h"
#include "libbfd.h"
#include "libiberty.h"
#include "libiberty.h"
#include "elf-bfd.h"
#include "elf-bfd.h"
#include "elf/score.h"
#include "elf/score.h"
#include "elf/common.h"
#include "elf/common.h"
#include "elf/internal.h"
#include "elf/internal.h"
#include "hashtab.h"
#include "hashtab.h"
#include "elf32-score.h"
#include "elf32-score.h"
 
 
 
 
int score3 = 0;
int score3 = 0;
int score7 = 1;
int score7 = 1;
 
 
/* The SCORE ELF linker needs additional information for each symbol in
/* The SCORE ELF linker needs additional information for each symbol in
   the global hash table.  */
   the global hash table.  */
struct score_elf_link_hash_entry
struct score_elf_link_hash_entry
{
{
  struct elf_link_hash_entry root;
  struct elf_link_hash_entry root;
 
 
  /* Number of R_SCORE_ABS32, R_SCORE_REL32 relocs against this symbol.  */
  /* Number of R_SCORE_ABS32, R_SCORE_REL32 relocs against this symbol.  */
  unsigned int possibly_dynamic_relocs;
  unsigned int possibly_dynamic_relocs;
 
 
  /* If the R_SCORE_ABS32, R_SCORE_REL32 reloc is against a readonly section.  */
  /* If the R_SCORE_ABS32, R_SCORE_REL32 reloc is against a readonly section.  */
  bfd_boolean readonly_reloc;
  bfd_boolean readonly_reloc;
 
 
  /* We must not create a stub for a symbol that has relocations related to
  /* We must not create a stub for a symbol that has relocations related to
     taking the function's address, i.e. any but R_SCORE_CALL15 ones.  */
     taking the function's address, i.e. any but R_SCORE_CALL15 ones.  */
  bfd_boolean no_fn_stub;
  bfd_boolean no_fn_stub;
 
 
  /* Are we forced local?  This will only be set if we have converted
  /* Are we forced local?  This will only be set if we have converted
     the initial global GOT entry to a local GOT entry.  */
     the initial global GOT entry to a local GOT entry.  */
  bfd_boolean forced_local;
  bfd_boolean forced_local;
};
};
 
 
/* Traverse a score ELF linker hash table.  */
/* Traverse a score ELF linker hash table.  */
#define score_elf_link_hash_traverse(table, func, info) \
#define score_elf_link_hash_traverse(table, func, info) \
  (elf_link_hash_traverse \
  (elf_link_hash_traverse \
   ((table),                                                         \
   ((table),                                                         \
    (bfd_boolean (*) (struct elf_link_hash_entry *, void *)) (func), \
    (bfd_boolean (*) (struct elf_link_hash_entry *, void *)) (func), \
    (info)))
    (info)))
 
 
/* This structure is used to hold .got entries while estimating got sizes.  */
/* This structure is used to hold .got entries while estimating got sizes.  */
struct score_got_entry
struct score_got_entry
{
{
  /* The input bfd in which the symbol is defined.  */
  /* The input bfd in which the symbol is defined.  */
  bfd *abfd;
  bfd *abfd;
  /* The index of the symbol, as stored in the relocation r_info, if
  /* The index of the symbol, as stored in the relocation r_info, if
     we have a local symbol; -1 otherwise.  */
     we have a local symbol; -1 otherwise.  */
  long symndx;
  long symndx;
  union
  union
  {
  {
    /* If abfd == NULL, an address that must be stored in the got.  */
    /* If abfd == NULL, an address that must be stored in the got.  */
    bfd_vma address;
    bfd_vma address;
    /* If abfd != NULL && symndx != -1, the addend of the relocation
    /* If abfd != NULL && symndx != -1, the addend of the relocation
       that should be added to the symbol value.  */
       that should be added to the symbol value.  */
    bfd_vma addend;
    bfd_vma addend;
    /* If abfd != NULL && symndx == -1, the hash table entry
    /* If abfd != NULL && symndx == -1, the hash table entry
       corresponding to a global symbol in the got (or, local, if
       corresponding to a global symbol in the got (or, local, if
       h->forced_local).  */
       h->forced_local).  */
    struct score_elf_link_hash_entry *h;
    struct score_elf_link_hash_entry *h;
  } d;
  } d;
 
 
  /* The offset from the beginning of the .got section to the entry
  /* The offset from the beginning of the .got section to the entry
     corresponding to this symbol+addend.  If it's a global symbol
     corresponding to this symbol+addend.  If it's a global symbol
     whose offset is yet to be decided, it's going to be -1.  */
     whose offset is yet to be decided, it's going to be -1.  */
  long gotidx;
  long gotidx;
};
};
 
 
/* This structure is passed to score_elf_sort_hash_table_f when sorting
/* This structure is passed to score_elf_sort_hash_table_f when sorting
   the dynamic symbols.  */
   the dynamic symbols.  */
 
 
struct score_elf_hash_sort_data
struct score_elf_hash_sort_data
{
{
  /* The symbol in the global GOT with the lowest dynamic symbol table index.  */
  /* The symbol in the global GOT with the lowest dynamic symbol table index.  */
  struct elf_link_hash_entry *low;
  struct elf_link_hash_entry *low;
  /* The least dynamic symbol table index corresponding to a symbol with a GOT entry.  */
  /* The least dynamic symbol table index corresponding to a symbol with a GOT entry.  */
  long min_got_dynindx;
  long min_got_dynindx;
  /* The greatest dynamic symbol table index corresponding to a symbol
  /* The greatest dynamic symbol table index corresponding to a symbol
     with a GOT entry that is not referenced (e.g., a dynamic symbol
     with a GOT entry that is not referenced (e.g., a dynamic symbol
     with dynamic relocations pointing to it from non-primary GOTs).  */
     with dynamic relocations pointing to it from non-primary GOTs).  */
  long max_unref_got_dynindx;
  long max_unref_got_dynindx;
  /* The greatest dynamic symbol table index not corresponding to a
  /* The greatest dynamic symbol table index not corresponding to a
     symbol without a GOT entry.  */
     symbol without a GOT entry.  */
  long max_non_got_dynindx;
  long max_non_got_dynindx;
};
};
 
 
struct score_got_info
struct score_got_info
{
{
  /* The global symbol in the GOT with the lowest index in the dynamic
  /* The global symbol in the GOT with the lowest index in the dynamic
     symbol table.  */
     symbol table.  */
  struct elf_link_hash_entry *global_gotsym;
  struct elf_link_hash_entry *global_gotsym;
  /* The number of global .got entries.  */
  /* The number of global .got entries.  */
  unsigned int global_gotno;
  unsigned int global_gotno;
  /* The number of local .got entries.  */
  /* The number of local .got entries.  */
  unsigned int local_gotno;
  unsigned int local_gotno;
  /* The number of local .got entries we have used.  */
  /* The number of local .got entries we have used.  */
  unsigned int assigned_gotno;
  unsigned int assigned_gotno;
  /* A hash table holding members of the got.  */
  /* A hash table holding members of the got.  */
  struct htab *got_entries;
  struct htab *got_entries;
  /* In multi-got links, a pointer to the next got (err, rather, most
  /* In multi-got links, a pointer to the next got (err, rather, most
     of the time, it points to the previous got).  */
     of the time, it points to the previous got).  */
  struct score_got_info *next;
  struct score_got_info *next;
};
};
 
 
/* A structure used to count GOT entries, for GOT entry or ELF symbol table traversal.  */
/* A structure used to count GOT entries, for GOT entry or ELF symbol table traversal.  */
struct _score_elf_section_data
struct _score_elf_section_data
{
{
  struct bfd_elf_section_data elf;
  struct bfd_elf_section_data elf;
  union
  union
  {
  {
    struct score_got_info *got_info;
    struct score_got_info *got_info;
    bfd_byte *tdata;
    bfd_byte *tdata;
  }
  }
  u;
  u;
};
};
 
 
#define score_elf_section_data(sec) \
#define score_elf_section_data(sec) \
  ((struct _score_elf_section_data *) elf_section_data (sec))
  ((struct _score_elf_section_data *) elf_section_data (sec))
 
 
/* The size of a symbol-table entry.  */
/* The size of a symbol-table entry.  */
#define SCORE_ELF_SYM_SIZE(abfd)  \
#define SCORE_ELF_SYM_SIZE(abfd)  \
  (get_elf_backend_data (abfd)->s->sizeof_sym)
  (get_elf_backend_data (abfd)->s->sizeof_sym)
 
 
/* In case we're on a 32-bit machine, construct a 64-bit "-1" value
/* In case we're on a 32-bit machine, construct a 64-bit "-1" value
   from smaller values.  Start with zero, widen, *then* decrement.  */
   from smaller values.  Start with zero, widen, *then* decrement.  */
#define MINUS_ONE (((bfd_vma)0) - 1)
#define MINUS_ONE (((bfd_vma)0) - 1)
#define MINUS_TWO (((bfd_vma)0) - 2)
#define MINUS_TWO (((bfd_vma)0) - 2)
 
 
#define PDR_SIZE 32
#define PDR_SIZE 32
 
 
 
 
/* The number of local .got entries we reserve.  */
/* The number of local .got entries we reserve.  */
#define SCORE_RESERVED_GOTNO (2)
#define SCORE_RESERVED_GOTNO (2)
#define ELF_DYNAMIC_INTERPRETER     "/usr/lib/ld.so.1"
#define ELF_DYNAMIC_INTERPRETER     "/usr/lib/ld.so.1"
 
 
/* The offset of $gp from the beginning of the .got section.  */
/* The offset of $gp from the beginning of the .got section.  */
#define ELF_SCORE_GP_OFFSET(abfd) (0x3ff0)
#define ELF_SCORE_GP_OFFSET(abfd) (0x3ff0)
/* The maximum size of the GOT for it to be addressable using 15-bit offsets from $gp.  */
/* The maximum size of the GOT for it to be addressable using 15-bit offsets from $gp.  */
#define SCORE_ELF_GOT_MAX_SIZE(abfd) (ELF_SCORE_GP_OFFSET(abfd) + 0x3fff)
#define SCORE_ELF_GOT_MAX_SIZE(abfd) (ELF_SCORE_GP_OFFSET(abfd) + 0x3fff)
 
 
#define SCORE_ELF_STUB_SECTION_NAME  (".SCORE.stub")
#define SCORE_ELF_STUB_SECTION_NAME  (".SCORE.stub")
#define SCORE_FUNCTION_STUB_SIZE (16)
#define SCORE_FUNCTION_STUB_SIZE (16)
 
 
#define STUB_LW      0xc3bcc010     /* lw r29, [r28, -0x3ff0]  */
#define STUB_LW      0xc3bcc010     /* lw r29, [r28, -0x3ff0]  */
#define STUB_MOVE    0x8363bc56     /* mv r27, r3  */
#define STUB_MOVE    0x8363bc56     /* mv r27, r3  */
#define STUB_LI16    0x87548000     /* ori r26, .dynsym_index  */
#define STUB_LI16    0x87548000     /* ori r26, .dynsym_index  */
#define STUB_BRL     0x801dbc09     /* brl r29  */
#define STUB_BRL     0x801dbc09     /* brl r29  */
 
 
#define SCORE_ELF_GOT_SIZE(abfd)   \
#define SCORE_ELF_GOT_SIZE(abfd)   \
  (get_elf_backend_data (abfd)->s->arch_size / 8)
  (get_elf_backend_data (abfd)->s->arch_size / 8)
 
 
#define SCORE_ELF_ADD_DYNAMIC_ENTRY(info, tag, val) \
#define SCORE_ELF_ADD_DYNAMIC_ENTRY(info, tag, val) \
        (_bfd_elf_add_dynamic_entry (info, (bfd_vma) tag, (bfd_vma) val))
        (_bfd_elf_add_dynamic_entry (info, (bfd_vma) tag, (bfd_vma) val))
 
 
/* The size of an external dynamic table entry.  */
/* The size of an external dynamic table entry.  */
#define SCORE_ELF_DYN_SIZE(abfd) \
#define SCORE_ELF_DYN_SIZE(abfd) \
  (get_elf_backend_data (abfd)->s->sizeof_dyn)
  (get_elf_backend_data (abfd)->s->sizeof_dyn)
 
 
/* The size of an external REL relocation.  */
/* The size of an external REL relocation.  */
#define SCORE_ELF_REL_SIZE(abfd) \
#define SCORE_ELF_REL_SIZE(abfd) \
  (get_elf_backend_data (abfd)->s->sizeof_rel)
  (get_elf_backend_data (abfd)->s->sizeof_rel)
 
 
/* The default alignment for sections, as a power of two.  */
/* The default alignment for sections, as a power of two.  */
#define SCORE_ELF_LOG_FILE_ALIGN(abfd)\
#define SCORE_ELF_LOG_FILE_ALIGN(abfd)\
  (get_elf_backend_data (abfd)->s->log_file_align)
  (get_elf_backend_data (abfd)->s->log_file_align)
 
 
static bfd_byte *hi16_rel_addr;
static bfd_byte *hi16_rel_addr;
 
 
/* This will be used when we sort the dynamic relocation records.  */
/* This will be used when we sort the dynamic relocation records.  */
static bfd *reldyn_sorting_bfd;
static bfd *reldyn_sorting_bfd;
 
 
/* SCORE ELF uses two common sections.  One is the usual one, and the
/* SCORE ELF uses two common sections.  One is the usual one, and the
   other is for small objects.  All the small objects are kept
   other is for small objects.  All the small objects are kept
   together, and then referenced via the gp pointer, which yields
   together, and then referenced via the gp pointer, which yields
   faster assembler code.  This is what we use for the small common
   faster assembler code.  This is what we use for the small common
   section.  This approach is copied from ecoff.c.  */
   section.  This approach is copied from ecoff.c.  */
static asection score_elf_scom_section;
static asection score_elf_scom_section;
static asymbol  score_elf_scom_symbol;
static asymbol  score_elf_scom_symbol;
static asymbol  *score_elf_scom_symbol_ptr;
static asymbol  *score_elf_scom_symbol_ptr;
 
 
static bfd_vma
static bfd_vma
score_bfd_get_16 (bfd *abfd, const void *data)
score_bfd_get_16 (bfd *abfd, const void *data)
{
{
  return bfd_get_16 (abfd, data);
  return bfd_get_16 (abfd, data);
}
}
 
 
static bfd_vma
static bfd_vma
score3_bfd_getl32 (const void *p)
score3_bfd_getl32 (const void *p)
{
{
  const bfd_byte *addr = p;
  const bfd_byte *addr = p;
  unsigned long v;
  unsigned long v;
 
 
  v = (unsigned long) addr[2];
  v = (unsigned long) addr[2];
  v |= (unsigned long) addr[3] << 8;
  v |= (unsigned long) addr[3] << 8;
  v |= (unsigned long) addr[0] << 16;
  v |= (unsigned long) addr[0] << 16;
  v |= (unsigned long) addr[1] << 24;
  v |= (unsigned long) addr[1] << 24;
  return v;
  return v;
}
}
 
 
static bfd_vma
static bfd_vma
score3_bfd_getl48 (const void *p)
score3_bfd_getl48 (const void *p)
{
{
  const bfd_byte *addr = p;
  const bfd_byte *addr = p;
  unsigned long long v;
  unsigned long long v;
 
 
  v = (unsigned long long) addr[4];
  v = (unsigned long long) addr[4];
  v |= (unsigned long long) addr[5] << 8;
  v |= (unsigned long long) addr[5] << 8;
  v |= (unsigned long long) addr[2] << 16;
  v |= (unsigned long long) addr[2] << 16;
  v |= (unsigned long long) addr[3] << 24;
  v |= (unsigned long long) addr[3] << 24;
  v |= (unsigned long long) addr[0] << 32;
  v |= (unsigned long long) addr[0] << 32;
  v |= (unsigned long long) addr[1] << 40;
  v |= (unsigned long long) addr[1] << 40;
  return v;
  return v;
}
}
 
 
static bfd_vma
static bfd_vma
score_bfd_get_32 (bfd *abfd, const void *data)
score_bfd_get_32 (bfd *abfd, const void *data)
{
{
  if (/* score3 && */ abfd->xvec->byteorder == BFD_ENDIAN_LITTLE)
  if (/* score3 && */ abfd->xvec->byteorder == BFD_ENDIAN_LITTLE)
    return score3_bfd_getl32 (data);
    return score3_bfd_getl32 (data);
  else
  else
    return bfd_get_32 (abfd, data);
    return bfd_get_32 (abfd, data);
}
}
 
 
static bfd_vma
static bfd_vma
score_bfd_get_48 (bfd *abfd, const void *p)
score_bfd_get_48 (bfd *abfd, const void *p)
{
{
  if (/* score3 && */ abfd->xvec->byteorder == BFD_ENDIAN_LITTLE)
  if (/* score3 && */ abfd->xvec->byteorder == BFD_ENDIAN_LITTLE)
    return score3_bfd_getl48 (p);
    return score3_bfd_getl48 (p);
  else
  else
    return bfd_get_bits (p, 48, 1);
    return bfd_get_bits (p, 48, 1);
}
}
 
 
static void
static void
score_bfd_put_16 (bfd *abfd, bfd_vma addr, void *data)
score_bfd_put_16 (bfd *abfd, bfd_vma addr, void *data)
{
{
  return bfd_put_16 (abfd, addr, data);
  return bfd_put_16 (abfd, addr, data);
}
}
 
 
static void
static void
score3_bfd_putl32 (bfd_vma data, void *p)
score3_bfd_putl32 (bfd_vma data, void *p)
{
{
  bfd_byte *addr = p;
  bfd_byte *addr = p;
  addr[0] = (data >> 16) & 0xff;
  addr[0] = (data >> 16) & 0xff;
  addr[1] = (data >> 24) & 0xff;
  addr[1] = (data >> 24) & 0xff;
  addr[2] = data & 0xff;
  addr[2] = data & 0xff;
  addr[3] = (data >>  8) & 0xff;
  addr[3] = (data >>  8) & 0xff;
}
}
 
 
static void
static void
score3_bfd_putl48 (bfd_vma data, void *p)
score3_bfd_putl48 (bfd_vma data, void *p)
{
{
  bfd_byte *addr = p;
  bfd_byte *addr = p;
  addr[0] = (data >> 32) & 0xff;
  addr[0] = (data >> 32) & 0xff;
  addr[1] = (data >> 40) & 0xff;
  addr[1] = (data >> 40) & 0xff;
  addr[2] = (data >> 16) & 0xff;
  addr[2] = (data >> 16) & 0xff;
  addr[3] = (data >> 24) & 0xff;
  addr[3] = (data >> 24) & 0xff;
  addr[4] = data & 0xff;
  addr[4] = data & 0xff;
  addr[5] = (data >>  8) & 0xff;
  addr[5] = (data >>  8) & 0xff;
}
}
 
 
static void
static void
score_bfd_put_32 (bfd *abfd, bfd_vma addr, void *data)
score_bfd_put_32 (bfd *abfd, bfd_vma addr, void *data)
{
{
  if (/* score3 && */ abfd->xvec->byteorder == BFD_ENDIAN_LITTLE)
  if (/* score3 && */ abfd->xvec->byteorder == BFD_ENDIAN_LITTLE)
    return score3_bfd_putl32 (addr, data);
    return score3_bfd_putl32 (addr, data);
  else
  else
    return bfd_put_32 (abfd, addr, data);
    return bfd_put_32 (abfd, addr, data);
}
}
 
 
static void
static void
score_bfd_put_48 (bfd *abfd, bfd_vma val, void *p)
score_bfd_put_48 (bfd *abfd, bfd_vma val, void *p)
{
{
  if (/* score3 && */ abfd->xvec->byteorder == BFD_ENDIAN_LITTLE)
  if (/* score3 && */ abfd->xvec->byteorder == BFD_ENDIAN_LITTLE)
    return score3_bfd_putl48 (val, p);
    return score3_bfd_putl48 (val, p);
  else
  else
    return bfd_put_bits (val, p, 48, 1);
    return bfd_put_bits (val, p, 48, 1);
}
}
 
 
static bfd_reloc_status_type
static bfd_reloc_status_type
score_elf_hi16_reloc (bfd *abfd ATTRIBUTE_UNUSED,
score_elf_hi16_reloc (bfd *abfd ATTRIBUTE_UNUSED,
                      arelent *reloc_entry,
                      arelent *reloc_entry,
                      asymbol *symbol ATTRIBUTE_UNUSED,
                      asymbol *symbol ATTRIBUTE_UNUSED,
                      void * data,
                      void * data,
                      asection *input_section ATTRIBUTE_UNUSED,
                      asection *input_section ATTRIBUTE_UNUSED,
                      bfd *output_bfd ATTRIBUTE_UNUSED,
                      bfd *output_bfd ATTRIBUTE_UNUSED,
                      char **error_message ATTRIBUTE_UNUSED)
                      char **error_message ATTRIBUTE_UNUSED)
{
{
  hi16_rel_addr = (bfd_byte *) data + reloc_entry->address;
  hi16_rel_addr = (bfd_byte *) data + reloc_entry->address;
  return bfd_reloc_ok;
  return bfd_reloc_ok;
}
}
 
 
static bfd_reloc_status_type
static bfd_reloc_status_type
score_elf_lo16_reloc (bfd *abfd,
score_elf_lo16_reloc (bfd *abfd,
                      arelent *reloc_entry,
                      arelent *reloc_entry,
                      asymbol *symbol ATTRIBUTE_UNUSED,
                      asymbol *symbol ATTRIBUTE_UNUSED,
                      void * data,
                      void * data,
                      asection *input_section,
                      asection *input_section,
                      bfd *output_bfd ATTRIBUTE_UNUSED,
                      bfd *output_bfd ATTRIBUTE_UNUSED,
                      char **error_message ATTRIBUTE_UNUSED)
                      char **error_message ATTRIBUTE_UNUSED)
{
{
  bfd_vma addend = 0, offset = 0;
  bfd_vma addend = 0, offset = 0;
  unsigned long val;
  unsigned long val;
  unsigned long hi16_offset, hi16_value, uvalue;
  unsigned long hi16_offset, hi16_value, uvalue;
 
 
  hi16_value = score_bfd_get_32 (abfd, hi16_rel_addr);
  hi16_value = score_bfd_get_32 (abfd, hi16_rel_addr);
  hi16_offset = ((((hi16_value >> 16) & 0x3) << 15) | (hi16_value & 0x7fff)) >> 1;
  hi16_offset = ((((hi16_value >> 16) & 0x3) << 15) | (hi16_value & 0x7fff)) >> 1;
  addend = score_bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
  addend = score_bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
  offset = ((((addend >> 16) & 0x3) << 15) | (addend & 0x7fff)) >> 1;
  offset = ((((addend >> 16) & 0x3) << 15) | (addend & 0x7fff)) >> 1;
  val = reloc_entry->addend;
  val = reloc_entry->addend;
  if (reloc_entry->address > input_section->size)
  if (reloc_entry->address > input_section->size)
    return bfd_reloc_outofrange;
    return bfd_reloc_outofrange;
  uvalue = ((hi16_offset << 16) | (offset & 0xffff)) + val;
  uvalue = ((hi16_offset << 16) | (offset & 0xffff)) + val;
  hi16_offset = (uvalue >> 16) << 1;
  hi16_offset = (uvalue >> 16) << 1;
  hi16_value = (hi16_value & ~0x37fff) | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000);
  hi16_value = (hi16_value & ~0x37fff) | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000);
  score_bfd_put_32 (abfd, hi16_value, hi16_rel_addr);
  score_bfd_put_32 (abfd, hi16_value, hi16_rel_addr);
  offset = (uvalue & 0xffff) << 1;
  offset = (uvalue & 0xffff) << 1;
  addend = (addend & ~0x37fff) | (offset & 0x7fff) | ((offset << 1) & 0x30000);
  addend = (addend & ~0x37fff) | (offset & 0x7fff) | ((offset << 1) & 0x30000);
  score_bfd_put_32 (abfd, addend, (bfd_byte *) data + reloc_entry->address);
  score_bfd_put_32 (abfd, addend, (bfd_byte *) data + reloc_entry->address);
  return bfd_reloc_ok;
  return bfd_reloc_ok;
}
}
 
 
/* Set the GP value for OUTPUT_BFD.  Returns FALSE if this is a
/* Set the GP value for OUTPUT_BFD.  Returns FALSE if this is a
   dangerous relocation.  */
   dangerous relocation.  */
 
 
static bfd_boolean
static bfd_boolean
score_elf_assign_gp (bfd *output_bfd, bfd_vma *pgp)
score_elf_assign_gp (bfd *output_bfd, bfd_vma *pgp)
{
{
  unsigned int count;
  unsigned int count;
  asymbol **sym;
  asymbol **sym;
  unsigned int i;
  unsigned int i;
 
 
  /* If we've already figured out what GP will be, just return it.  */
  /* If we've already figured out what GP will be, just return it.  */
  *pgp = _bfd_get_gp_value (output_bfd);
  *pgp = _bfd_get_gp_value (output_bfd);
  if (*pgp)
  if (*pgp)
    return TRUE;
    return TRUE;
 
 
  count = bfd_get_symcount (output_bfd);
  count = bfd_get_symcount (output_bfd);
  sym = bfd_get_outsymbols (output_bfd);
  sym = bfd_get_outsymbols (output_bfd);
 
 
  /* The linker script will have created a symbol named `_gp' with the
  /* The linker script will have created a symbol named `_gp' with the
     appropriate value.  */
     appropriate value.  */
  if (sym == NULL)
  if (sym == NULL)
    i = count;
    i = count;
  else
  else
    {
    {
      for (i = 0; i < count; i++, sym++)
      for (i = 0; i < count; i++, sym++)
        {
        {
          const char *name;
          const char *name;
 
 
          name = bfd_asymbol_name (*sym);
          name = bfd_asymbol_name (*sym);
          if (*name == '_' && strcmp (name, "_gp") == 0)
          if (*name == '_' && strcmp (name, "_gp") == 0)
            {
            {
              *pgp = bfd_asymbol_value (*sym);
              *pgp = bfd_asymbol_value (*sym);
              _bfd_set_gp_value (output_bfd, *pgp);
              _bfd_set_gp_value (output_bfd, *pgp);
              break;
              break;
            }
            }
        }
        }
    }
    }
 
 
  if (i >= count)
  if (i >= count)
    {
    {
      /* Only get the error once.  */
      /* Only get the error once.  */
      *pgp = 4;
      *pgp = 4;
      _bfd_set_gp_value (output_bfd, *pgp);
      _bfd_set_gp_value (output_bfd, *pgp);
      return FALSE;
      return FALSE;
    }
    }
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* We have to figure out the gp value, so that we can adjust the
/* We have to figure out the gp value, so that we can adjust the
   symbol value correctly.  We look up the symbol _gp in the output
   symbol value correctly.  We look up the symbol _gp in the output
   BFD.  If we can't find it, we're stuck.  We cache it in the ELF
   BFD.  If we can't find it, we're stuck.  We cache it in the ELF
   target data.  We don't need to adjust the symbol value for an
   target data.  We don't need to adjust the symbol value for an
   external symbol if we are producing relocatable output.  */
   external symbol if we are producing relocatable output.  */
static bfd_reloc_status_type
static bfd_reloc_status_type
score_elf_final_gp (bfd *output_bfd,
score_elf_final_gp (bfd *output_bfd,
                    asymbol *symbol,
                    asymbol *symbol,
                    bfd_boolean relocatable,
                    bfd_boolean relocatable,
                     char **error_message,
                     char **error_message,
                    bfd_vma *pgp)
                    bfd_vma *pgp)
{
{
  if (bfd_is_und_section (symbol->section)
  if (bfd_is_und_section (symbol->section)
      && ! relocatable)
      && ! relocatable)
    {
    {
      *pgp = 0;
      *pgp = 0;
      return bfd_reloc_undefined;
      return bfd_reloc_undefined;
    }
    }
 
 
  *pgp = _bfd_get_gp_value (output_bfd);
  *pgp = _bfd_get_gp_value (output_bfd);
  if (*pgp == 0
  if (*pgp == 0
      && (! relocatable
      && (! relocatable
          || (symbol->flags & BSF_SECTION_SYM) != 0))
          || (symbol->flags & BSF_SECTION_SYM) != 0))
    {
    {
      if (relocatable)
      if (relocatable)
        {
        {
          /* Make up a value.  */
          /* Make up a value.  */
          *pgp = symbol->section->output_section->vma + 0x4000;
          *pgp = symbol->section->output_section->vma + 0x4000;
          _bfd_set_gp_value (output_bfd, *pgp);
          _bfd_set_gp_value (output_bfd, *pgp);
        }
        }
      else if (!score_elf_assign_gp (output_bfd, pgp))
      else if (!score_elf_assign_gp (output_bfd, pgp))
        {
        {
            *error_message =
            *error_message =
              (char *) _("GP relative relocation when _gp not defined");
              (char *) _("GP relative relocation when _gp not defined");
            return bfd_reloc_dangerous;
            return bfd_reloc_dangerous;
        }
        }
    }
    }
 
 
  return bfd_reloc_ok;
  return bfd_reloc_ok;
}
}
 
 
static bfd_reloc_status_type
static bfd_reloc_status_type
score_elf_gprel15_with_gp (bfd *abfd,
score_elf_gprel15_with_gp (bfd *abfd,
                           asymbol *symbol,
                           asymbol *symbol,
                           arelent *reloc_entry,
                           arelent *reloc_entry,
                           asection *input_section,
                           asection *input_section,
                           bfd_boolean relocateable,
                           bfd_boolean relocateable,
                           void * data,
                           void * data,
                           bfd_vma gp ATTRIBUTE_UNUSED)
                           bfd_vma gp ATTRIBUTE_UNUSED)
{
{
  bfd_vma relocation;
  bfd_vma relocation;
  unsigned long insn;
  unsigned long insn;
 
 
  if (bfd_is_com_section (symbol->section))
  if (bfd_is_com_section (symbol->section))
    relocation = 0;
    relocation = 0;
  else
  else
    relocation = symbol->value;
    relocation = symbol->value;
 
 
  relocation += symbol->section->output_section->vma;
  relocation += symbol->section->output_section->vma;
  relocation += symbol->section->output_offset;
  relocation += symbol->section->output_offset;
  if (reloc_entry->address > input_section->size)
  if (reloc_entry->address > input_section->size)
    return bfd_reloc_outofrange;
    return bfd_reloc_outofrange;
 
 
  insn = score_bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
  insn = score_bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
  if (((reloc_entry->addend & 0xffffc000) != 0)
  if (((reloc_entry->addend & 0xffffc000) != 0)
      && ((reloc_entry->addend & 0xffffc000) != 0xffffc000))
      && ((reloc_entry->addend & 0xffffc000) != 0xffffc000))
    return bfd_reloc_overflow;
    return bfd_reloc_overflow;
 
 
  insn = (insn & ~0x7fff) | (reloc_entry->addend & 0x7fff);
  insn = (insn & ~0x7fff) | (reloc_entry->addend & 0x7fff);
  score_bfd_put_32 (abfd, insn, (bfd_byte *) data + reloc_entry->address);
  score_bfd_put_32 (abfd, insn, (bfd_byte *) data + reloc_entry->address);
  if (relocateable)
  if (relocateable)
    reloc_entry->address += input_section->output_offset;
    reloc_entry->address += input_section->output_offset;
 
 
  return bfd_reloc_ok;
  return bfd_reloc_ok;
}
}
 
 
static bfd_reloc_status_type
static bfd_reloc_status_type
gprel32_with_gp (bfd *abfd, asymbol *symbol, arelent *reloc_entry,
gprel32_with_gp (bfd *abfd, asymbol *symbol, arelent *reloc_entry,
                 asection *input_section, bfd_boolean relocatable,
                 asection *input_section, bfd_boolean relocatable,
                 void *data, bfd_vma gp)
                 void *data, bfd_vma gp)
{
{
  bfd_vma relocation;
  bfd_vma relocation;
  bfd_vma val;
  bfd_vma val;
 
 
  if (bfd_is_com_section (symbol->section))
  if (bfd_is_com_section (symbol->section))
    relocation = 0;
    relocation = 0;
  else
  else
    relocation = symbol->value;
    relocation = symbol->value;
 
 
  relocation += symbol->section->output_section->vma;
  relocation += symbol->section->output_section->vma;
  relocation += symbol->section->output_offset;
  relocation += symbol->section->output_offset;
 
 
  if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
  if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
    return bfd_reloc_outofrange;
    return bfd_reloc_outofrange;
 
 
  /* Set val to the offset into the section or symbol.  */
  /* Set val to the offset into the section or symbol.  */
  val = reloc_entry->addend;
  val = reloc_entry->addend;
 
 
  if (reloc_entry->howto->partial_inplace)
  if (reloc_entry->howto->partial_inplace)
    val += score_bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
    val += score_bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
 
 
  /* Adjust val for the final section location and GP value.  If we
  /* Adjust val for the final section location and GP value.  If we
     are producing relocatable output, we don't want to do this for
     are producing relocatable output, we don't want to do this for
     an external symbol.  */
     an external symbol.  */
  if (! relocatable
  if (! relocatable
      || (symbol->flags & BSF_SECTION_SYM) != 0)
      || (symbol->flags & BSF_SECTION_SYM) != 0)
    val += relocation - gp;
    val += relocation - gp;
 
 
  if (reloc_entry->howto->partial_inplace)
  if (reloc_entry->howto->partial_inplace)
    score_bfd_put_32 (abfd, val, (bfd_byte *) data + reloc_entry->address);
    score_bfd_put_32 (abfd, val, (bfd_byte *) data + reloc_entry->address);
  else
  else
    reloc_entry->addend = val;
    reloc_entry->addend = val;
 
 
  if (relocatable)
  if (relocatable)
    reloc_entry->address += input_section->output_offset;
    reloc_entry->address += input_section->output_offset;
 
 
  return bfd_reloc_ok;
  return bfd_reloc_ok;
}
}
 
 
static bfd_reloc_status_type
static bfd_reloc_status_type
score_elf_gprel15_reloc (bfd *abfd,
score_elf_gprel15_reloc (bfd *abfd,
                         arelent *reloc_entry,
                         arelent *reloc_entry,
                         asymbol *symbol,
                         asymbol *symbol,
                         void * data,
                         void * data,
                         asection *input_section,
                         asection *input_section,
                         bfd *output_bfd,
                         bfd *output_bfd,
                         char **error_message)
                         char **error_message)
{
{
  bfd_boolean relocateable;
  bfd_boolean relocateable;
  bfd_reloc_status_type ret;
  bfd_reloc_status_type ret;
  bfd_vma gp;
  bfd_vma gp;
 
 
  if (output_bfd != NULL
  if (output_bfd != NULL
      && (symbol->flags & BSF_SECTION_SYM) == 0 && reloc_entry->addend == 0)
      && (symbol->flags & BSF_SECTION_SYM) == 0 && reloc_entry->addend == 0)
    {
    {
      reloc_entry->address += input_section->output_offset;
      reloc_entry->address += input_section->output_offset;
      return bfd_reloc_ok;
      return bfd_reloc_ok;
    }
    }
  if (output_bfd != NULL)
  if (output_bfd != NULL)
    relocateable = TRUE;
    relocateable = TRUE;
  else
  else
    {
    {
      relocateable = FALSE;
      relocateable = FALSE;
      output_bfd = symbol->section->output_section->owner;
      output_bfd = symbol->section->output_section->owner;
    }
    }
 
 
  ret = score_elf_final_gp (output_bfd, symbol, relocateable, error_message, &gp);
  ret = score_elf_final_gp (output_bfd, symbol, relocateable, error_message, &gp);
  if (ret != bfd_reloc_ok)
  if (ret != bfd_reloc_ok)
    return ret;
    return ret;
 
 
  return score_elf_gprel15_with_gp (abfd, symbol, reloc_entry,
  return score_elf_gprel15_with_gp (abfd, symbol, reloc_entry,
                                         input_section, relocateable, data, gp);
                                         input_section, relocateable, data, gp);
}
}
 
 
/* Do a R_SCORE_GPREL32 relocation.  This is a 32 bit value which must
/* Do a R_SCORE_GPREL32 relocation.  This is a 32 bit value which must
   become the offset from the gp register.  */
   become the offset from the gp register.  */
 
 
static bfd_reloc_status_type
static bfd_reloc_status_type
score_elf_gprel32_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
score_elf_gprel32_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
                        void *data, asection *input_section, bfd *output_bfd,
                        void *data, asection *input_section, bfd *output_bfd,
                        char **error_message)
                        char **error_message)
{
{
  bfd_boolean relocatable;
  bfd_boolean relocatable;
  bfd_reloc_status_type ret;
  bfd_reloc_status_type ret;
  bfd_vma gp;
  bfd_vma gp;
 
 
  /* R_SCORE_GPREL32 relocations are defined for local symbols only.  */
  /* R_SCORE_GPREL32 relocations are defined for local symbols only.  */
  if (output_bfd != NULL
  if (output_bfd != NULL
      && (symbol->flags & BSF_SECTION_SYM) == 0
      && (symbol->flags & BSF_SECTION_SYM) == 0
      && (symbol->flags & BSF_LOCAL) != 0)
      && (symbol->flags & BSF_LOCAL) != 0)
    {
    {
      *error_message = (char *)
      *error_message = (char *)
        _("32bits gp relative relocation occurs for an external symbol");
        _("32bits gp relative relocation occurs for an external symbol");
      return bfd_reloc_outofrange;
      return bfd_reloc_outofrange;
    }
    }
 
 
  if (output_bfd != NULL)
  if (output_bfd != NULL)
    relocatable = TRUE;
    relocatable = TRUE;
  else
  else
    {
    {
      relocatable = FALSE;
      relocatable = FALSE;
      output_bfd = symbol->section->output_section->owner;
      output_bfd = symbol->section->output_section->owner;
    }
    }
 
 
  ret = score_elf_final_gp (output_bfd, symbol, relocatable, error_message, &gp);
  ret = score_elf_final_gp (output_bfd, symbol, relocatable, error_message, &gp);
  if (ret != bfd_reloc_ok)
  if (ret != bfd_reloc_ok)
    return ret;
    return ret;
 
 
  gp = 0;
  gp = 0;
  return gprel32_with_gp (abfd, symbol, reloc_entry, input_section,
  return gprel32_with_gp (abfd, symbol, reloc_entry, input_section,
                          relocatable, data, gp);
                          relocatable, data, gp);
}
}
 
 
/* A howto special_function for R_SCORE_GOT15 relocations.  This is just
/* A howto special_function for R_SCORE_GOT15 relocations.  This is just
   like any other 16-bit relocation when applied to global symbols, but is
   like any other 16-bit relocation when applied to global symbols, but is
   treated in the same as R_SCORE_HI16 when applied to local symbols.  */
   treated in the same as R_SCORE_HI16 when applied to local symbols.  */
static bfd_reloc_status_type
static bfd_reloc_status_type
score_elf_got15_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
score_elf_got15_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
                       void *data, asection *input_section,
                       void *data, asection *input_section,
                       bfd *output_bfd, char **error_message)
                       bfd *output_bfd, char **error_message)
{
{
  if ((symbol->flags & (BSF_GLOBAL | BSF_WEAK)) != 0
  if ((symbol->flags & (BSF_GLOBAL | BSF_WEAK)) != 0
      || bfd_is_und_section (bfd_get_section (symbol))
      || bfd_is_und_section (bfd_get_section (symbol))
      || bfd_is_com_section (bfd_get_section (symbol)))
      || bfd_is_com_section (bfd_get_section (symbol)))
    /* The relocation is against a global symbol.  */
    /* The relocation is against a global symbol.  */
    return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
    return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
                                  input_section, output_bfd,
                                  input_section, output_bfd,
                                  error_message);
                                  error_message);
 
 
  return score_elf_hi16_reloc (abfd, reloc_entry, symbol, data,
  return score_elf_hi16_reloc (abfd, reloc_entry, symbol, data,
                               input_section, output_bfd, error_message);
                               input_section, output_bfd, error_message);
}
}
 
 
static bfd_reloc_status_type
static bfd_reloc_status_type
score_elf_got_lo16_reloc (bfd *abfd,
score_elf_got_lo16_reloc (bfd *abfd,
                          arelent *reloc_entry,
                          arelent *reloc_entry,
                          asymbol *symbol ATTRIBUTE_UNUSED,
                          asymbol *symbol ATTRIBUTE_UNUSED,
                          void * data,
                          void * data,
                          asection *input_section,
                          asection *input_section,
                          bfd *output_bfd ATTRIBUTE_UNUSED,
                          bfd *output_bfd ATTRIBUTE_UNUSED,
                          char **error_message ATTRIBUTE_UNUSED)
                          char **error_message ATTRIBUTE_UNUSED)
{
{
  bfd_vma addend = 0, offset = 0;
  bfd_vma addend = 0, offset = 0;
  signed long val;
  signed long val;
  signed long hi16_offset, hi16_value, uvalue;
  signed long hi16_offset, hi16_value, uvalue;
 
 
  hi16_value = score_bfd_get_32 (abfd, hi16_rel_addr);
  hi16_value = score_bfd_get_32 (abfd, hi16_rel_addr);
  hi16_offset = ((((hi16_value >> 16) & 0x3) << 15) | (hi16_value & 0x7fff)) >> 1;
  hi16_offset = ((((hi16_value >> 16) & 0x3) << 15) | (hi16_value & 0x7fff)) >> 1;
  addend = score_bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
  addend = score_bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
  offset = ((((addend >> 16) & 0x3) << 15) | (addend & 0x7fff)) >> 1;
  offset = ((((addend >> 16) & 0x3) << 15) | (addend & 0x7fff)) >> 1;
  val = reloc_entry->addend;
  val = reloc_entry->addend;
  if (reloc_entry->address > input_section->size)
  if (reloc_entry->address > input_section->size)
    return bfd_reloc_outofrange;
    return bfd_reloc_outofrange;
  uvalue = ((hi16_offset << 16) | (offset & 0xffff)) + val;
  uvalue = ((hi16_offset << 16) | (offset & 0xffff)) + val;
  if ((uvalue > -0x8000) && (uvalue < 0x7fff))
  if ((uvalue > -0x8000) && (uvalue < 0x7fff))
    hi16_offset = 0;
    hi16_offset = 0;
  else
  else
    hi16_offset = (uvalue >> 16) & 0x7fff;
    hi16_offset = (uvalue >> 16) & 0x7fff;
  hi16_value = (hi16_value & ~0x37fff) | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000);
  hi16_value = (hi16_value & ~0x37fff) | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000);
  score_bfd_put_32 (abfd, hi16_value, hi16_rel_addr);
  score_bfd_put_32 (abfd, hi16_value, hi16_rel_addr);
  offset = (uvalue & 0xffff) << 1;
  offset = (uvalue & 0xffff) << 1;
  addend = (addend & ~0x37fff) | (offset & 0x7fff) | ((offset << 1) & 0x30000);
  addend = (addend & ~0x37fff) | (offset & 0x7fff) | ((offset << 1) & 0x30000);
  score_bfd_put_32 (abfd, addend, (bfd_byte *) data + reloc_entry->address);
  score_bfd_put_32 (abfd, addend, (bfd_byte *) data + reloc_entry->address);
  return bfd_reloc_ok;
  return bfd_reloc_ok;
}
}
 
 
static reloc_howto_type elf32_score_howto_table[] =
static reloc_howto_type elf32_score_howto_table[] =
{
{
  /* No relocation.  */
  /* No relocation.  */
  HOWTO (R_SCORE_NONE,          /* type */
  HOWTO (R_SCORE_NONE,          /* type */
         0,                     /* rightshift */
         0,                     /* rightshift */
         0,                     /* size (0 = byte, 1 = short, 2 = long) */
         0,                     /* size (0 = byte, 1 = short, 2 = long) */
         0,                     /* bitsize */
         0,                     /* bitsize */
         FALSE,                 /* pc_relative */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         0,                     /* bitpos */
         complain_overflow_dont,/* complain_on_overflow */
         complain_overflow_dont,/* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         bfd_elf_generic_reloc, /* special_function */
         "R_SCORE_NONE",        /* name */
         "R_SCORE_NONE",        /* name */
         FALSE,                 /* partial_inplace */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0,                     /* src_mask */
         0,                     /* dst_mask */
         0,                     /* dst_mask */
         FALSE),                /* pcrel_offset */
         FALSE),                /* pcrel_offset */
 
 
  /* R_SCORE_HI16 */
  /* R_SCORE_HI16 */
  HOWTO (R_SCORE_HI16,          /* type */
  HOWTO (R_SCORE_HI16,          /* type */
         0,                     /* rightshift */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
         16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         FALSE,                 /* pc_relative */
         1,                     /* bitpos */
         1,                     /* bitpos */
         complain_overflow_dont,/* complain_on_overflow */
         complain_overflow_dont,/* complain_on_overflow */
         score_elf_hi16_reloc,  /* special_function */
         score_elf_hi16_reloc,  /* special_function */
         "R_SCORE_HI16",        /* name */
         "R_SCORE_HI16",        /* name */
         TRUE,                  /* partial_inplace */
         TRUE,                  /* partial_inplace */
         0x37fff,               /* src_mask */
         0x37fff,               /* src_mask */
         0x37fff,               /* dst_mask */
         0x37fff,               /* dst_mask */
         FALSE),                /* pcrel_offset */
         FALSE),                /* pcrel_offset */
 
 
  /* R_SCORE_LO16 */
  /* R_SCORE_LO16 */
  HOWTO (R_SCORE_LO16,          /* type */
  HOWTO (R_SCORE_LO16,          /* type */
         0,                     /* rightshift */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
         16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         FALSE,                 /* pc_relative */
         1,                     /* bitpos */
         1,                     /* bitpos */
         complain_overflow_dont,/* complain_on_overflow */
         complain_overflow_dont,/* complain_on_overflow */
         score_elf_lo16_reloc,  /* special_function */
         score_elf_lo16_reloc,  /* special_function */
         "R_SCORE_LO16",        /* name */
         "R_SCORE_LO16",        /* name */
         TRUE,                  /* partial_inplace */
         TRUE,                  /* partial_inplace */
         0x37fff,               /* src_mask */
         0x37fff,               /* src_mask */
         0x37fff,               /* dst_mask */
         0x37fff,               /* dst_mask */
         FALSE),                /* pcrel_offset */
         FALSE),                /* pcrel_offset */
 
 
  /*  R_SCORE_BCMP */
  /*  R_SCORE_BCMP */
  HOWTO (R_SCORE_BCMP,          /* type */
  HOWTO (R_SCORE_BCMP,          /* type */
         1,                     /* rightshift */
         1,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
         16,                    /* bitsize */
         TRUE,                  /* pc_relative */
         TRUE,                  /* pc_relative */
         1,                     /* bitpos */
         1,                     /* bitpos */
         complain_overflow_dont,/* complain_on_overflow */
         complain_overflow_dont,/* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         bfd_elf_generic_reloc, /* special_function */
         "R_SCORE_BCMP",        /* name */
         "R_SCORE_BCMP",        /* name */
         FALSE,                 /* partial_inplace */
         FALSE,                 /* partial_inplace */
         0x03e00381,            /* src_mask */
         0x03e00381,            /* src_mask */
         0x03e00381,            /* dst_mask */
         0x03e00381,            /* dst_mask */
         FALSE),                /* pcrel_offset */
         FALSE),                /* pcrel_offset */
 
 
  /*R_SCORE_24 */
  /*R_SCORE_24 */
  HOWTO (R_SCORE_24,            /* type */
  HOWTO (R_SCORE_24,            /* type */
         1,                     /* rightshift */
         1,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         24,                    /* bitsize */
         24,                    /* bitsize */
         FALSE,                 /* pc_relative */
         FALSE,                 /* pc_relative */
         1,                     /* bitpos */
         1,                     /* bitpos */
         complain_overflow_dont,/* complain_on_overflow */
         complain_overflow_dont,/* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         bfd_elf_generic_reloc, /* special_function */
         "R_SCORE_24",          /* name */
         "R_SCORE_24",          /* name */
         FALSE,                 /* partial_inplace */
         FALSE,                 /* partial_inplace */
         0x3ff7fff,             /* src_mask */
         0x3ff7fff,             /* src_mask */
         0x3ff7fff,             /* dst_mask */
         0x3ff7fff,             /* dst_mask */
         FALSE),                /* pcrel_offset */
         FALSE),                /* pcrel_offset */
 
 
  /*R_SCORE_PC19 */
  /*R_SCORE_PC19 */
  HOWTO (R_SCORE_PC19,          /* type */
  HOWTO (R_SCORE_PC19,          /* type */
         1,                     /* rightshift */
         1,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         19,                    /* bitsize */
         19,                    /* bitsize */
         TRUE,                  /* pc_relative */
         TRUE,                  /* pc_relative */
         1,                     /* bitpos */
         1,                     /* bitpos */
         complain_overflow_dont,/* complain_on_overflow */
         complain_overflow_dont,/* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         bfd_elf_generic_reloc, /* special_function */
         "R_SCORE_PC19",        /* name */
         "R_SCORE_PC19",        /* name */
         FALSE,                 /* partial_inplace */
         FALSE,                 /* partial_inplace */
         0x3ff03fe,             /* src_mask */
         0x3ff03fe,             /* src_mask */
         0x3ff03fe,             /* dst_mask */
         0x3ff03fe,             /* dst_mask */
         FALSE),                /* pcrel_offset */
         FALSE),                /* pcrel_offset */
 
 
  /*R_SCORE16_11 */
  /*R_SCORE16_11 */
  HOWTO (R_SCORE16_11,          /* type */
  HOWTO (R_SCORE16_11,          /* type */
         1,                     /* rightshift */
         1,                     /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         11,                    /* bitsize */
         11,                    /* bitsize */
         FALSE,                 /* pc_relative */
         FALSE,                 /* pc_relative */
         1,                     /* bitpos */
         1,                     /* bitpos */
         complain_overflow_dont,/* complain_on_overflow */
         complain_overflow_dont,/* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         bfd_elf_generic_reloc, /* special_function */
         "R_SCORE16_11",        /* name */
         "R_SCORE16_11",        /* name */
         FALSE,                 /* partial_inplace */
         FALSE,                 /* partial_inplace */
         0x000000ffe,           /* src_mask */
         0x000000ffe,           /* src_mask */
         0x000000ffe,           /* dst_mask */
         0x000000ffe,           /* dst_mask */
         FALSE),                /* pcrel_offset */
         FALSE),                /* pcrel_offset */
 
 
  /* R_SCORE16_PC8 */
  /* R_SCORE16_PC8 */
  HOWTO (R_SCORE16_PC8,         /* type */
  HOWTO (R_SCORE16_PC8,         /* type */
         1,                     /* rightshift */
         1,                     /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         9,                     /* bitsize */
         9,                     /* bitsize */
         TRUE,                  /* pc_relative */
         TRUE,                  /* pc_relative */
         0,                     /* bitpos */
         0,                     /* bitpos */
         complain_overflow_dont,/* complain_on_overflow */
         complain_overflow_dont,/* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         bfd_elf_generic_reloc, /* special_function */
         "R_SCORE16_PC8",       /* name */
         "R_SCORE16_PC8",       /* name */
         FALSE,                 /* partial_inplace */
         FALSE,                 /* partial_inplace */
         0x000001ff,            /* src_mask */
         0x000001ff,            /* src_mask */
         0x000001ff,            /* dst_mask */
         0x000001ff,            /* dst_mask */
         FALSE),                /* pcrel_offset */
         FALSE),                /* pcrel_offset */
 
 
  /* 32 bit absolute */
  /* 32 bit absolute */
  HOWTO (R_SCORE_ABS32,         /* type  8 */
  HOWTO (R_SCORE_ABS32,         /* type  8 */
         0,                     /* rightshift */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         32,                    /* bitsize */
         32,                    /* bitsize */
         FALSE,                 /* pc_relative */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         0,                     /* bitpos */
         complain_overflow_bitfield,    /* complain_on_overflow */
         complain_overflow_bitfield,    /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         bfd_elf_generic_reloc, /* special_function */
         "R_SCORE_ABS32",       /* name */
         "R_SCORE_ABS32",       /* name */
         FALSE,                 /* partial_inplace */
         FALSE,                 /* partial_inplace */
         0xffffffff,            /* src_mask */
         0xffffffff,            /* src_mask */
         0xffffffff,            /* dst_mask */
         0xffffffff,            /* dst_mask */
         FALSE),                /* pcrel_offset */
         FALSE),                /* pcrel_offset */
 
 
  /* 16 bit absolute */
  /* 16 bit absolute */
  HOWTO (R_SCORE_ABS16,         /* type 11 */
  HOWTO (R_SCORE_ABS16,         /* type 11 */
         0,                     /* rightshift */
         0,                     /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
         16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         0,                     /* bitpos */
         complain_overflow_bitfield,    /* complain_on_overflow */
         complain_overflow_bitfield,    /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         bfd_elf_generic_reloc, /* special_function */
         "R_SCORE_ABS16",       /* name */
         "R_SCORE_ABS16",       /* name */
         FALSE,                 /* partial_inplace */
         FALSE,                 /* partial_inplace */
         0x0000ffff,            /* src_mask */
         0x0000ffff,            /* src_mask */
         0x0000ffff,            /* dst_mask */
         0x0000ffff,            /* dst_mask */
         FALSE),                /* pcrel_offset */
         FALSE),                /* pcrel_offset */
 
 
  /* R_SCORE_DUMMY2 */
  /* R_SCORE_DUMMY2 */
  HOWTO (R_SCORE_DUMMY2,        /* type */
  HOWTO (R_SCORE_DUMMY2,        /* type */
         0,                     /* rightshift */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
         16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         0,                     /* bitpos */
         complain_overflow_dont,/* complain_on_overflow */
         complain_overflow_dont,/* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         bfd_elf_generic_reloc, /* special_function */
         "R_SCORE_DUMMY2",      /* name */
         "R_SCORE_DUMMY2",      /* name */
         TRUE,                  /* partial_inplace */
         TRUE,                  /* partial_inplace */
         0x00007fff,            /* src_mask */
         0x00007fff,            /* src_mask */
         0x00007fff,            /* dst_mask */
         0x00007fff,            /* dst_mask */
         FALSE),                /* pcrel_offset */
         FALSE),                /* pcrel_offset */
 
 
  /* R_SCORE_GP15 */
  /* R_SCORE_GP15 */
  HOWTO (R_SCORE_GP15,          /* type */
  HOWTO (R_SCORE_GP15,          /* type */
         0,                     /* rightshift */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
         16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         0,                     /* bitpos */
         complain_overflow_dont,/* complain_on_overflow */
         complain_overflow_dont,/* complain_on_overflow */
         score_elf_gprel15_reloc,/* special_function */
         score_elf_gprel15_reloc,/* special_function */
         "R_SCORE_GP15",        /* name */
         "R_SCORE_GP15",        /* name */
         TRUE,                  /* partial_inplace */
         TRUE,                  /* partial_inplace */
         0x00007fff,            /* src_mask */
         0x00007fff,            /* src_mask */
         0x00007fff,            /* dst_mask */
         0x00007fff,            /* dst_mask */
         FALSE),                /* pcrel_offset */
         FALSE),                /* pcrel_offset */
 
 
  /* GNU extension to record C++ vtable hierarchy.  */
  /* GNU extension to record C++ vtable hierarchy.  */
  HOWTO (R_SCORE_GNU_VTINHERIT, /* type */
  HOWTO (R_SCORE_GNU_VTINHERIT, /* type */
         0,                     /* rightshift */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         0,                     /* bitsize */
         0,                     /* bitsize */
         FALSE,                 /* pc_relative */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         0,                     /* bitpos */
         complain_overflow_dont,/* complain_on_overflow */
         complain_overflow_dont,/* complain_on_overflow */
         NULL,                  /* special_function */
         NULL,                  /* special_function */
         "R_SCORE_GNU_VTINHERIT",       /* name */
         "R_SCORE_GNU_VTINHERIT",       /* name */
         FALSE,                 /* partial_inplace */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0,                     /* src_mask */
         0,                     /* dst_mask */
         0,                     /* dst_mask */
         FALSE),                /* pcrel_offset */
         FALSE),                /* pcrel_offset */
 
 
  /* GNU extension to record C++ vtable member usage */
  /* GNU extension to record C++ vtable member usage */
  HOWTO (R_SCORE_GNU_VTENTRY,   /* type */
  HOWTO (R_SCORE_GNU_VTENTRY,   /* type */
         0,                     /* rightshift */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         0,                     /* bitsize */
         0,                     /* bitsize */
         FALSE,                 /* pc_relative */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         0,                     /* bitpos */
         complain_overflow_dont,/* complain_on_overflow */
         complain_overflow_dont,/* complain_on_overflow */
         _bfd_elf_rel_vtable_reloc_fn,  /* special_function */
         _bfd_elf_rel_vtable_reloc_fn,  /* special_function */
         "R_SCORE_GNU_VTENTRY", /* name */
         "R_SCORE_GNU_VTENTRY", /* name */
         FALSE,                 /* partial_inplace */
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0,                     /* src_mask */
         0,                     /* dst_mask */
         0,                     /* dst_mask */
         FALSE),                /* pcrel_offset */
         FALSE),                /* pcrel_offset */
 
 
  /* Reference to global offset table.  */
  /* Reference to global offset table.  */
  HOWTO (R_SCORE_GOT15,         /* type */
  HOWTO (R_SCORE_GOT15,         /* type */
         0,                     /* rightshift */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
         16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         0,                     /* bitpos */
         complain_overflow_signed,      /* complain_on_overflow */
         complain_overflow_signed,      /* complain_on_overflow */
         score_elf_got15_reloc, /* special_function */
         score_elf_got15_reloc, /* special_function */
         "R_SCORE_GOT15",       /* name */
         "R_SCORE_GOT15",       /* name */
         TRUE,                  /* partial_inplace */
         TRUE,                  /* partial_inplace */
         0x00007fff,            /* src_mask */
         0x00007fff,            /* src_mask */
         0x00007fff,            /* dst_mask */
         0x00007fff,            /* dst_mask */
         FALSE),                /* pcrel_offset */
         FALSE),                /* pcrel_offset */
 
 
  /* Low 16 bits of displacement in global offset table.  */
  /* Low 16 bits of displacement in global offset table.  */
  HOWTO (R_SCORE_GOT_LO16,      /* type */
  HOWTO (R_SCORE_GOT_LO16,      /* type */
         0,                     /* rightshift */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
         16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         FALSE,                 /* pc_relative */
         1,                     /* bitpos */
         1,                     /* bitpos */
         complain_overflow_dont,/* complain_on_overflow */
         complain_overflow_dont,/* complain_on_overflow */
         score_elf_got_lo16_reloc, /* special_function */
         score_elf_got_lo16_reloc, /* special_function */
         "R_SCORE_GOT_LO16",    /* name */
         "R_SCORE_GOT_LO16",    /* name */
         TRUE,                  /* partial_inplace */
         TRUE,                  /* partial_inplace */
         0x37ffe,               /* src_mask */
         0x37ffe,               /* src_mask */
         0x37ffe,               /* dst_mask */
         0x37ffe,               /* dst_mask */
         FALSE),                /* pcrel_offset */
         FALSE),                /* pcrel_offset */
 
 
  /* 15 bit call through global offset table.  */
  /* 15 bit call through global offset table.  */
  HOWTO (R_SCORE_CALL15,        /* type */
  HOWTO (R_SCORE_CALL15,        /* type */
         0,                     /* rightshift */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
         16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
         complain_overflow_signed, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         bfd_elf_generic_reloc, /* special_function */
         "R_SCORE_CALL15",      /* name */
         "R_SCORE_CALL15",      /* name */
         TRUE,                  /* partial_inplace */
         TRUE,                  /* partial_inplace */
         0x0000ffff,            /* src_mask */
         0x0000ffff,            /* src_mask */
         0x0000ffff,            /* dst_mask */
         0x0000ffff,            /* dst_mask */
         FALSE),                /* pcrel_offset */
         FALSE),                /* pcrel_offset */
 
 
  /* 32 bit GP relative reference.  */
  /* 32 bit GP relative reference.  */
  HOWTO (R_SCORE_GPREL32,       /* type */
  HOWTO (R_SCORE_GPREL32,       /* type */
         0,                     /* rightshift */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         32,                    /* bitsize */
         32,                    /* bitsize */
         FALSE,                 /* pc_relative */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         0,                     /* bitpos */
         complain_overflow_dont,/* complain_on_overflow */
         complain_overflow_dont,/* complain_on_overflow */
         score_elf_gprel32_reloc, /* special_function */
         score_elf_gprel32_reloc, /* special_function */
         "R_SCORE_GPREL32",     /* name */
         "R_SCORE_GPREL32",     /* name */
         TRUE,                  /* partial_inplace */
         TRUE,                  /* partial_inplace */
         0xffffffff,            /* src_mask */
         0xffffffff,            /* src_mask */
         0xffffffff,            /* dst_mask */
         0xffffffff,            /* dst_mask */
         FALSE),                /* pcrel_offset */
         FALSE),                /* pcrel_offset */
 
 
  /* 32 bit symbol relative relocation.  */
  /* 32 bit symbol relative relocation.  */
  HOWTO (R_SCORE_REL32,         /* type */
  HOWTO (R_SCORE_REL32,         /* type */
         0,                     /* rightshift */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         32,                    /* bitsize */
         32,                    /* bitsize */
         FALSE,                 /* pc_relative */
         FALSE,                 /* pc_relative */
         0,                     /* bitpos */
         0,                     /* bitpos */
         complain_overflow_dont,/* complain_on_overflow */
         complain_overflow_dont,/* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         bfd_elf_generic_reloc, /* special_function */
         "R_SCORE_REL32",       /* name */
         "R_SCORE_REL32",       /* name */
         TRUE,                  /* partial_inplace */
         TRUE,                  /* partial_inplace */
         0xffffffff,            /* src_mask */
         0xffffffff,            /* src_mask */
         0xffffffff,            /* dst_mask */
         0xffffffff,            /* dst_mask */
         FALSE),                /* pcrel_offset */
         FALSE),                /* pcrel_offset */
 
 
  /* R_SCORE_DUMMY_HI16 */
  /* R_SCORE_DUMMY_HI16 */
  HOWTO (R_SCORE_DUMMY_HI16,    /* type */
  HOWTO (R_SCORE_DUMMY_HI16,    /* type */
         0,                     /* rightshift */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
         16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         FALSE,                 /* pc_relative */
         1,                     /* bitpos */
         1,                     /* bitpos */
         complain_overflow_dont,/* complain_on_overflow */
         complain_overflow_dont,/* complain_on_overflow */
         score_elf_hi16_reloc,  /* special_function */
         score_elf_hi16_reloc,  /* special_function */
         "R_SCORE_DUMMY_HI16",  /* name */
         "R_SCORE_DUMMY_HI16",  /* name */
         TRUE,                  /* partial_inplace */
         TRUE,                  /* partial_inplace */
         0x37fff,               /* src_mask */
         0x37fff,               /* src_mask */
         0x37fff,               /* dst_mask */
         0x37fff,               /* dst_mask */
         FALSE),                /* pcrel_offset */
         FALSE),                /* pcrel_offset */
 
 
  /* R_SCORE_IMM30 */
  /* R_SCORE_IMM30 */
  HOWTO (R_SCORE_IMM30,         /* type */
  HOWTO (R_SCORE_IMM30,         /* type */
         2,                     /* rightshift */
         2,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         30,                    /* bitsize */
         30,                    /* bitsize */
         FALSE,                 /* pc_relative */
         FALSE,                 /* pc_relative */
         7,                     /* bitpos */
         7,                     /* bitpos */
         complain_overflow_dont,/* complain_on_overflow */
         complain_overflow_dont,/* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         bfd_elf_generic_reloc, /* special_function */
         "R_SCORE_IMM30",       /* name */
         "R_SCORE_IMM30",       /* name */
         FALSE,                 /* partial_inplace */
         FALSE,                 /* partial_inplace */
         0x7f7fff7f80LL,        /* src_mask */
         0x7f7fff7f80LL,        /* src_mask */
         0x7f7fff7f80LL,        /* dst_mask */
         0x7f7fff7f80LL,        /* dst_mask */
         FALSE),                /* pcrel_offset */
         FALSE),                /* pcrel_offset */
 
 
  /* R_SCORE_IMM32 */
  /* R_SCORE_IMM32 */
  HOWTO (R_SCORE_IMM32,         /* type */
  HOWTO (R_SCORE_IMM32,         /* type */
         0,                     /* rightshift */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         32,                    /* bitsize */
         32,                    /* bitsize */
         FALSE,                 /* pc_relative */
         FALSE,                 /* pc_relative */
         5,                     /* bitpos */
         5,                     /* bitpos */
         complain_overflow_dont,/* complain_on_overflow */
         complain_overflow_dont,/* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         bfd_elf_generic_reloc, /* special_function */
         "R_SCORE_IMM32",       /* name */
         "R_SCORE_IMM32",       /* name */
         FALSE,                 /* partial_inplace */
         FALSE,                 /* partial_inplace */
         0x7f7fff7fe0LL,        /* src_mask */
         0x7f7fff7fe0LL,        /* src_mask */
         0x7f7fff7fe0LL,        /* dst_mask */
         0x7f7fff7fe0LL,        /* dst_mask */
         FALSE),                /* pcrel_offset */
         FALSE),                /* pcrel_offset */
};
};
 
 
struct score_reloc_map
struct score_reloc_map
{
{
  bfd_reloc_code_real_type bfd_reloc_val;
  bfd_reloc_code_real_type bfd_reloc_val;
  unsigned char elf_reloc_val;
  unsigned char elf_reloc_val;
};
};
 
 
static const struct score_reloc_map elf32_score_reloc_map[] =
static const struct score_reloc_map elf32_score_reloc_map[] =
{
{
  {BFD_RELOC_NONE,               R_SCORE_NONE},
  {BFD_RELOC_NONE,               R_SCORE_NONE},
  {BFD_RELOC_HI16_S,             R_SCORE_HI16},
  {BFD_RELOC_HI16_S,             R_SCORE_HI16},
  {BFD_RELOC_LO16,               R_SCORE_LO16},
  {BFD_RELOC_LO16,               R_SCORE_LO16},
  {BFD_RELOC_SCORE_BCMP,         R_SCORE_BCMP},
  {BFD_RELOC_SCORE_BCMP,         R_SCORE_BCMP},
  {BFD_RELOC_SCORE_JMP,          R_SCORE_24},
  {BFD_RELOC_SCORE_JMP,          R_SCORE_24},
  {BFD_RELOC_SCORE_BRANCH,       R_SCORE_PC19},
  {BFD_RELOC_SCORE_BRANCH,       R_SCORE_PC19},
  {BFD_RELOC_SCORE16_JMP,        R_SCORE16_11},
  {BFD_RELOC_SCORE16_JMP,        R_SCORE16_11},
  {BFD_RELOC_SCORE16_BRANCH,     R_SCORE16_PC8},
  {BFD_RELOC_SCORE16_BRANCH,     R_SCORE16_PC8},
  {BFD_RELOC_32,                 R_SCORE_ABS32},
  {BFD_RELOC_32,                 R_SCORE_ABS32},
  {BFD_RELOC_16,                 R_SCORE_ABS16},
  {BFD_RELOC_16,                 R_SCORE_ABS16},
  {BFD_RELOC_SCORE_DUMMY2,       R_SCORE_DUMMY2},
  {BFD_RELOC_SCORE_DUMMY2,       R_SCORE_DUMMY2},
  {BFD_RELOC_SCORE_GPREL15,      R_SCORE_GP15},
  {BFD_RELOC_SCORE_GPREL15,      R_SCORE_GP15},
  {BFD_RELOC_VTABLE_INHERIT,     R_SCORE_GNU_VTINHERIT},
  {BFD_RELOC_VTABLE_INHERIT,     R_SCORE_GNU_VTINHERIT},
  {BFD_RELOC_VTABLE_ENTRY,       R_SCORE_GNU_VTENTRY},
  {BFD_RELOC_VTABLE_ENTRY,       R_SCORE_GNU_VTENTRY},
  {BFD_RELOC_SCORE_GOT15,        R_SCORE_GOT15},
  {BFD_RELOC_SCORE_GOT15,        R_SCORE_GOT15},
  {BFD_RELOC_SCORE_GOT_LO16,     R_SCORE_GOT_LO16},
  {BFD_RELOC_SCORE_GOT_LO16,     R_SCORE_GOT_LO16},
  {BFD_RELOC_SCORE_CALL15,       R_SCORE_CALL15},
  {BFD_RELOC_SCORE_CALL15,       R_SCORE_CALL15},
  {BFD_RELOC_GPREL32,            R_SCORE_GPREL32},
  {BFD_RELOC_GPREL32,            R_SCORE_GPREL32},
  {BFD_RELOC_32_PCREL,           R_SCORE_REL32},
  {BFD_RELOC_32_PCREL,           R_SCORE_REL32},
  {BFD_RELOC_SCORE_DUMMY_HI16,   R_SCORE_DUMMY_HI16},
  {BFD_RELOC_SCORE_DUMMY_HI16,   R_SCORE_DUMMY_HI16},
  {BFD_RELOC_SCORE_IMM30,        R_SCORE_IMM30},
  {BFD_RELOC_SCORE_IMM30,        R_SCORE_IMM30},
  {BFD_RELOC_SCORE_IMM32,        R_SCORE_IMM32},
  {BFD_RELOC_SCORE_IMM32,        R_SCORE_IMM32},
};
};
 
 
/* got_entries only match if they're identical, except for gotidx, so
/* got_entries only match if they're identical, except for gotidx, so
   use all fields to compute the hash, and compare the appropriate
   use all fields to compute the hash, and compare the appropriate
   union members.  */
   union members.  */
static hashval_t
static hashval_t
score_elf_got_entry_hash (const void *entry_)
score_elf_got_entry_hash (const void *entry_)
{
{
  const struct score_got_entry *entry = (struct score_got_entry *)entry_;
  const struct score_got_entry *entry = (struct score_got_entry *)entry_;
 
 
  return entry->symndx
  return entry->symndx
    + (!entry->abfd ? entry->d.address : entry->abfd->id);
    + (!entry->abfd ? entry->d.address : entry->abfd->id);
}
}
 
 
static int
static int
score_elf_got_entry_eq (const void *entry1, const void *entry2)
score_elf_got_entry_eq (const void *entry1, const void *entry2)
{
{
  const struct score_got_entry *e1 = (struct score_got_entry *)entry1;
  const struct score_got_entry *e1 = (struct score_got_entry *)entry1;
  const struct score_got_entry *e2 = (struct score_got_entry *)entry2;
  const struct score_got_entry *e2 = (struct score_got_entry *)entry2;
 
 
  return e1->abfd == e2->abfd && e1->symndx == e2->symndx
  return e1->abfd == e2->abfd && e1->symndx == e2->symndx
    && (! e1->abfd ? e1->d.address == e2->d.address
    && (! e1->abfd ? e1->d.address == e2->d.address
        : e1->symndx >= 0 ? e1->d.addend == e2->d.addend
        : e1->symndx >= 0 ? e1->d.addend == e2->d.addend
        : e1->d.h == e2->d.h);
        : e1->d.h == e2->d.h);
}
}
 
 
/* If H needs a GOT entry, assign it the highest available dynamic
/* If H needs a GOT entry, assign it the highest available dynamic
   index.  Otherwise, assign it the lowest available dynamic
   index.  Otherwise, assign it the lowest available dynamic
   index.  */
   index.  */
static bfd_boolean
static bfd_boolean
score_elf_sort_hash_table_f (struct score_elf_link_hash_entry *h, void *data)
score_elf_sort_hash_table_f (struct score_elf_link_hash_entry *h, void *data)
{
{
  struct score_elf_hash_sort_data *hsd = data;
  struct score_elf_hash_sort_data *hsd = data;
 
 
  if (h->root.root.type == bfd_link_hash_warning)
  if (h->root.root.type == bfd_link_hash_warning)
    h = (struct score_elf_link_hash_entry *) h->root.root.u.i.link;
    h = (struct score_elf_link_hash_entry *) h->root.root.u.i.link;
 
 
  /* Symbols without dynamic symbol table entries aren't interesting at all.  */
  /* Symbols without dynamic symbol table entries aren't interesting at all.  */
  if (h->root.dynindx == -1)
  if (h->root.dynindx == -1)
    return TRUE;
    return TRUE;
 
 
  /* Global symbols that need GOT entries that are not explicitly
  /* Global symbols that need GOT entries that are not explicitly
     referenced are marked with got offset 2.  Those that are
     referenced are marked with got offset 2.  Those that are
     referenced get a 1, and those that don't need GOT entries get
     referenced get a 1, and those that don't need GOT entries get
     -1.  */
     -1.  */
  if (h->root.got.offset == 2)
  if (h->root.got.offset == 2)
    {
    {
      if (hsd->max_unref_got_dynindx == hsd->min_got_dynindx)
      if (hsd->max_unref_got_dynindx == hsd->min_got_dynindx)
        hsd->low = (struct elf_link_hash_entry *) h;
        hsd->low = (struct elf_link_hash_entry *) h;
      h->root.dynindx = hsd->max_unref_got_dynindx++;
      h->root.dynindx = hsd->max_unref_got_dynindx++;
    }
    }
  else if (h->root.got.offset != 1)
  else if (h->root.got.offset != 1)
    h->root.dynindx = hsd->max_non_got_dynindx++;
    h->root.dynindx = hsd->max_non_got_dynindx++;
  else
  else
    {
    {
      h->root.dynindx = --hsd->min_got_dynindx;
      h->root.dynindx = --hsd->min_got_dynindx;
      hsd->low = (struct elf_link_hash_entry *) h;
      hsd->low = (struct elf_link_hash_entry *) h;
    }
    }
 
 
  return TRUE;
  return TRUE;
}
}
 
 
static asection *
static asection *
score_elf_got_section (bfd *abfd, bfd_boolean maybe_excluded)
score_elf_got_section (bfd *abfd, bfd_boolean maybe_excluded)
{
{
  asection *sgot = bfd_get_section_by_name (abfd, ".got");
  asection *sgot = bfd_get_section_by_name (abfd, ".got");
 
 
  if (sgot == NULL || (! maybe_excluded && (sgot->flags & SEC_EXCLUDE) != 0))
  if (sgot == NULL || (! maybe_excluded && (sgot->flags & SEC_EXCLUDE) != 0))
    return NULL;
    return NULL;
  return sgot;
  return sgot;
}
}
 
 
/* Returns the GOT information associated with the link indicated by
/* Returns the GOT information associated with the link indicated by
   INFO.  If SGOTP is non-NULL, it is filled in with the GOT section.  */
   INFO.  If SGOTP is non-NULL, it is filled in with the GOT section.  */
static struct score_got_info *
static struct score_got_info *
score_elf_got_info (bfd *abfd, asection **sgotp)
score_elf_got_info (bfd *abfd, asection **sgotp)
{
{
  asection *sgot;
  asection *sgot;
  struct score_got_info *g;
  struct score_got_info *g;
 
 
  sgot = score_elf_got_section (abfd, TRUE);
  sgot = score_elf_got_section (abfd, TRUE);
  BFD_ASSERT (sgot != NULL);
  BFD_ASSERT (sgot != NULL);
  BFD_ASSERT (elf_section_data (sgot) != NULL);
  BFD_ASSERT (elf_section_data (sgot) != NULL);
  g = score_elf_section_data (sgot)->u.got_info;
  g = score_elf_section_data (sgot)->u.got_info;
  BFD_ASSERT (g != NULL);
  BFD_ASSERT (g != NULL);
 
 
  if (sgotp)
  if (sgotp)
    *sgotp = sgot;
    *sgotp = sgot;
  return g;
  return g;
}
}
 
 
/* Sort the dynamic symbol table so that symbols that need GOT entries
/* Sort the dynamic symbol table so that symbols that need GOT entries
   appear towards the end.  This reduces the amount of GOT space
   appear towards the end.  This reduces the amount of GOT space
   required.  MAX_LOCAL is used to set the number of local symbols
   required.  MAX_LOCAL is used to set the number of local symbols
   known to be in the dynamic symbol table.  During
   known to be in the dynamic symbol table.  During
   s3_bfd_score_elf_size_dynamic_sections, this value is 1.  Afterward, the
   s3_bfd_score_elf_size_dynamic_sections, this value is 1.  Afterward, the
   section symbols are added and the count is higher.  */
   section symbols are added and the count is higher.  */
static bfd_boolean
static bfd_boolean
score_elf_sort_hash_table (struct bfd_link_info *info,
score_elf_sort_hash_table (struct bfd_link_info *info,
                           unsigned long max_local)
                           unsigned long max_local)
{
{
  struct score_elf_hash_sort_data hsd;
  struct score_elf_hash_sort_data hsd;
  struct score_got_info *g;
  struct score_got_info *g;
  bfd *dynobj;
  bfd *dynobj;
 
 
  dynobj = elf_hash_table (info)->dynobj;
  dynobj = elf_hash_table (info)->dynobj;
 
 
  g = score_elf_got_info (dynobj, NULL);
  g = score_elf_got_info (dynobj, NULL);
 
 
  hsd.low = NULL;
  hsd.low = NULL;
  hsd.max_unref_got_dynindx =
  hsd.max_unref_got_dynindx =
    hsd.min_got_dynindx = elf_hash_table (info)->dynsymcount
    hsd.min_got_dynindx = elf_hash_table (info)->dynsymcount
    /* In the multi-got case, assigned_gotno of the master got_info
    /* In the multi-got case, assigned_gotno of the master got_info
       indicate the number of entries that aren't referenced in the
       indicate the number of entries that aren't referenced in the
       primary GOT, but that must have entries because there are
       primary GOT, but that must have entries because there are
       dynamic relocations that reference it.  Since they aren't
       dynamic relocations that reference it.  Since they aren't
       referenced, we move them to the end of the GOT, so that they
       referenced, we move them to the end of the GOT, so that they
       don't prevent other entries that are referenced from getting
       don't prevent other entries that are referenced from getting
       too large offsets.  */
       too large offsets.  */
    - (g->next ? g->assigned_gotno : 0);
    - (g->next ? g->assigned_gotno : 0);
  hsd.max_non_got_dynindx = max_local;
  hsd.max_non_got_dynindx = max_local;
  score_elf_link_hash_traverse (elf_hash_table (info),
  score_elf_link_hash_traverse (elf_hash_table (info),
                                score_elf_sort_hash_table_f,
                                score_elf_sort_hash_table_f,
                                &hsd);
                                &hsd);
 
 
  /* There should have been enough room in the symbol table to
  /* There should have been enough room in the symbol table to
     accommodate both the GOT and non-GOT symbols.  */
     accommodate both the GOT and non-GOT symbols.  */
  BFD_ASSERT (hsd.max_non_got_dynindx <= hsd.min_got_dynindx);
  BFD_ASSERT (hsd.max_non_got_dynindx <= hsd.min_got_dynindx);
  BFD_ASSERT ((unsigned long)hsd.max_unref_got_dynindx
  BFD_ASSERT ((unsigned long)hsd.max_unref_got_dynindx
              <= elf_hash_table (info)->dynsymcount);
              <= elf_hash_table (info)->dynsymcount);
 
 
  /* Now we know which dynamic symbol has the lowest dynamic symbol
  /* Now we know which dynamic symbol has the lowest dynamic symbol
     table index in the GOT.  */
     table index in the GOT.  */
  g->global_gotsym = hsd.low;
  g->global_gotsym = hsd.low;
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* Create an entry in an score ELF linker hash table.  */
/* Create an entry in an score ELF linker hash table.  */
 
 
static struct bfd_hash_entry *
static struct bfd_hash_entry *
score_elf_link_hash_newfunc (struct bfd_hash_entry *entry,
score_elf_link_hash_newfunc (struct bfd_hash_entry *entry,
                             struct bfd_hash_table *table,
                             struct bfd_hash_table *table,
                             const char *string)
                             const char *string)
{
{
  struct score_elf_link_hash_entry *ret = (struct score_elf_link_hash_entry *) entry;
  struct score_elf_link_hash_entry *ret = (struct score_elf_link_hash_entry *) entry;
 
 
  /* Allocate the structure if it has not already been allocated by a subclass.  */
  /* Allocate the structure if it has not already been allocated by a subclass.  */
  if (ret == NULL)
  if (ret == NULL)
    ret = bfd_hash_allocate (table, sizeof (struct score_elf_link_hash_entry));
    ret = bfd_hash_allocate (table, sizeof (struct score_elf_link_hash_entry));
  if (ret == NULL)
  if (ret == NULL)
    return (struct bfd_hash_entry *) ret;
    return (struct bfd_hash_entry *) ret;
 
 
  /* Call the allocation method of the superclass.  */
  /* Call the allocation method of the superclass.  */
  ret = ((struct score_elf_link_hash_entry *)
  ret = ((struct score_elf_link_hash_entry *)
         _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
         _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
 
 
  if (ret != NULL)
  if (ret != NULL)
    {
    {
      ret->possibly_dynamic_relocs = 0;
      ret->possibly_dynamic_relocs = 0;
      ret->readonly_reloc = FALSE;
      ret->readonly_reloc = FALSE;
      ret->no_fn_stub = FALSE;
      ret->no_fn_stub = FALSE;
      ret->forced_local = FALSE;
      ret->forced_local = FALSE;
    }
    }
 
 
  return (struct bfd_hash_entry *) ret;
  return (struct bfd_hash_entry *) ret;
}
}
 
 
/* Returns the first relocation of type r_type found, beginning with
/* Returns the first relocation of type r_type found, beginning with
   RELOCATION.  RELEND is one-past-the-end of the relocation table.  */
   RELOCATION.  RELEND is one-past-the-end of the relocation table.  */
static const Elf_Internal_Rela *
static const Elf_Internal_Rela *
score_elf_next_relocation (bfd *abfd ATTRIBUTE_UNUSED, unsigned int r_type,
score_elf_next_relocation (bfd *abfd ATTRIBUTE_UNUSED, unsigned int r_type,
                            const Elf_Internal_Rela *relocation,
                            const Elf_Internal_Rela *relocation,
                           const Elf_Internal_Rela *relend)
                           const Elf_Internal_Rela *relend)
{
{
  while (relocation < relend)
  while (relocation < relend)
    {
    {
      if (ELF32_R_TYPE (relocation->r_info) == r_type)
      if (ELF32_R_TYPE (relocation->r_info) == r_type)
        return relocation;
        return relocation;
 
 
      ++relocation;
      ++relocation;
    }
    }
 
 
  /* We didn't find it.  */
  /* We didn't find it.  */
  bfd_set_error (bfd_error_bad_value);
  bfd_set_error (bfd_error_bad_value);
  return NULL;
  return NULL;
}
}
 
 
/* This function is called via qsort() to sort the dynamic relocation
/* This function is called via qsort() to sort the dynamic relocation
   entries by increasing r_symndx value.  */
   entries by increasing r_symndx value.  */
static int
static int
score_elf_sort_dynamic_relocs (const void *arg1, const void *arg2)
score_elf_sort_dynamic_relocs (const void *arg1, const void *arg2)
{
{
  Elf_Internal_Rela int_reloc1;
  Elf_Internal_Rela int_reloc1;
  Elf_Internal_Rela int_reloc2;
  Elf_Internal_Rela int_reloc2;
 
 
  bfd_elf32_swap_reloc_in (reldyn_sorting_bfd, arg1, &int_reloc1);
  bfd_elf32_swap_reloc_in (reldyn_sorting_bfd, arg1, &int_reloc1);
  bfd_elf32_swap_reloc_in (reldyn_sorting_bfd, arg2, &int_reloc2);
  bfd_elf32_swap_reloc_in (reldyn_sorting_bfd, arg2, &int_reloc2);
 
 
  return (ELF32_R_SYM (int_reloc1.r_info) - ELF32_R_SYM (int_reloc2.r_info));
  return (ELF32_R_SYM (int_reloc1.r_info) - ELF32_R_SYM (int_reloc2.r_info));
}
}
 
 
/* Return whether a relocation is against a local symbol.  */
/* Return whether a relocation is against a local symbol.  */
static bfd_boolean
static bfd_boolean
score_elf_local_relocation_p (bfd *input_bfd,
score_elf_local_relocation_p (bfd *input_bfd,
                              const Elf_Internal_Rela *relocation,
                              const Elf_Internal_Rela *relocation,
                              asection **local_sections,
                              asection **local_sections,
                              bfd_boolean check_forced)
                              bfd_boolean check_forced)
{
{
  unsigned long r_symndx;
  unsigned long r_symndx;
  Elf_Internal_Shdr *symtab_hdr;
  Elf_Internal_Shdr *symtab_hdr;
  struct score_elf_link_hash_entry *h;
  struct score_elf_link_hash_entry *h;
  size_t extsymoff;
  size_t extsymoff;
 
 
  r_symndx = ELF32_R_SYM (relocation->r_info);
  r_symndx = ELF32_R_SYM (relocation->r_info);
  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
  extsymoff = (elf_bad_symtab (input_bfd)) ? 0 : symtab_hdr->sh_info;
  extsymoff = (elf_bad_symtab (input_bfd)) ? 0 : symtab_hdr->sh_info;
 
 
  if (r_symndx < extsymoff)
  if (r_symndx < extsymoff)
    return TRUE;
    return TRUE;
  if (elf_bad_symtab (input_bfd) && local_sections[r_symndx] != NULL)
  if (elf_bad_symtab (input_bfd) && local_sections[r_symndx] != NULL)
    return TRUE;
    return TRUE;
 
 
  if (check_forced)
  if (check_forced)
    {
    {
      /* Look up the hash table to check whether the symbol was forced local.  */
      /* Look up the hash table to check whether the symbol was forced local.  */
      h = (struct score_elf_link_hash_entry *)
      h = (struct score_elf_link_hash_entry *)
        elf_sym_hashes (input_bfd) [r_symndx - extsymoff];
        elf_sym_hashes (input_bfd) [r_symndx - extsymoff];
      /* Find the real hash-table entry for this symbol.  */
      /* Find the real hash-table entry for this symbol.  */
      while (h->root.root.type == bfd_link_hash_indirect
      while (h->root.root.type == bfd_link_hash_indirect
             || h->root.root.type == bfd_link_hash_warning)
             || h->root.root.type == bfd_link_hash_warning)
        h = (struct score_elf_link_hash_entry *) h->root.root.u.i.link;
        h = (struct score_elf_link_hash_entry *) h->root.root.u.i.link;
      if (h->root.forced_local)
      if (h->root.forced_local)
        return TRUE;
        return TRUE;
    }
    }
 
 
  return FALSE;
  return FALSE;
}
}
 
 
/* Returns the dynamic relocation section for DYNOBJ.  */
/* Returns the dynamic relocation section for DYNOBJ.  */
static asection *
static asection *
score_elf_rel_dyn_section (bfd *dynobj, bfd_boolean create_p)
score_elf_rel_dyn_section (bfd *dynobj, bfd_boolean create_p)
{
{
  static const char dname[] = ".rel.dyn";
  static const char dname[] = ".rel.dyn";
  asection *sreloc;
  asection *sreloc;
 
 
  sreloc = bfd_get_section_by_name (dynobj, dname);
  sreloc = bfd_get_section_by_name (dynobj, dname);
  if (sreloc == NULL && create_p)
  if (sreloc == NULL && create_p)
    {
    {
      sreloc = bfd_make_section_with_flags (dynobj, dname,
      sreloc = bfd_make_section_with_flags (dynobj, dname,
                                            (SEC_ALLOC
                                            (SEC_ALLOC
                                             | SEC_LOAD
                                             | SEC_LOAD
                                             | SEC_HAS_CONTENTS
                                             | SEC_HAS_CONTENTS
                                             | SEC_IN_MEMORY
                                             | SEC_IN_MEMORY
                                             | SEC_LINKER_CREATED
                                             | SEC_LINKER_CREATED
                                             | SEC_READONLY));
                                             | SEC_READONLY));
      if (sreloc == NULL
      if (sreloc == NULL
          || ! bfd_set_section_alignment (dynobj, sreloc,
          || ! bfd_set_section_alignment (dynobj, sreloc,
                                          SCORE_ELF_LOG_FILE_ALIGN (dynobj)))
                                          SCORE_ELF_LOG_FILE_ALIGN (dynobj)))
        return NULL;
        return NULL;
    }
    }
  return sreloc;
  return sreloc;
}
}
 
 
static void
static void
score_elf_allocate_dynamic_relocations (bfd *abfd, unsigned int n)
score_elf_allocate_dynamic_relocations (bfd *abfd, unsigned int n)
{
{
  asection *s;
  asection *s;
 
 
  s = score_elf_rel_dyn_section (abfd, FALSE);
  s = score_elf_rel_dyn_section (abfd, FALSE);
  BFD_ASSERT (s != NULL);
  BFD_ASSERT (s != NULL);
 
 
  if (s->size == 0)
  if (s->size == 0)
    {
    {
      /* Make room for a null element.  */
      /* Make room for a null element.  */
      s->size += SCORE_ELF_REL_SIZE (abfd);
      s->size += SCORE_ELF_REL_SIZE (abfd);
      ++s->reloc_count;
      ++s->reloc_count;
    }
    }
  s->size += n * SCORE_ELF_REL_SIZE (abfd);
  s->size += n * SCORE_ELF_REL_SIZE (abfd);
}
}
 
 
/* Create a rel.dyn relocation for the dynamic linker to resolve.  REL
/* Create a rel.dyn relocation for the dynamic linker to resolve.  REL
   is the original relocation, which is now being transformed into a
   is the original relocation, which is now being transformed into a
   dynamic relocation.  The ADDENDP is adjusted if necessary; the
   dynamic relocation.  The ADDENDP is adjusted if necessary; the
   caller should store the result in place of the original addend.  */
   caller should store the result in place of the original addend.  */
static bfd_boolean
static bfd_boolean
score_elf_create_dynamic_relocation (bfd *output_bfd,
score_elf_create_dynamic_relocation (bfd *output_bfd,
                                     struct bfd_link_info *info,
                                     struct bfd_link_info *info,
                                     const Elf_Internal_Rela *rel,
                                     const Elf_Internal_Rela *rel,
                                     struct score_elf_link_hash_entry *h,
                                     struct score_elf_link_hash_entry *h,
                                     bfd_vma symbol,
                                     bfd_vma symbol,
                                     bfd_vma *addendp, asection *input_section)
                                     bfd_vma *addendp, asection *input_section)
{
{
  Elf_Internal_Rela outrel[3];
  Elf_Internal_Rela outrel[3];
  asection *sreloc;
  asection *sreloc;
  bfd *dynobj;
  bfd *dynobj;
  int r_type;
  int r_type;
  long indx;
  long indx;
  bfd_boolean defined_p;
  bfd_boolean defined_p;
 
 
  r_type = ELF32_R_TYPE (rel->r_info);
  r_type = ELF32_R_TYPE (rel->r_info);
  dynobj = elf_hash_table (info)->dynobj;
  dynobj = elf_hash_table (info)->dynobj;
  sreloc = score_elf_rel_dyn_section (dynobj, FALSE);
  sreloc = score_elf_rel_dyn_section (dynobj, FALSE);
  BFD_ASSERT (sreloc != NULL);
  BFD_ASSERT (sreloc != NULL);
  BFD_ASSERT (sreloc->contents != NULL);
  BFD_ASSERT (sreloc->contents != NULL);
  BFD_ASSERT (sreloc->reloc_count * SCORE_ELF_REL_SIZE (output_bfd) < sreloc->size);
  BFD_ASSERT (sreloc->reloc_count * SCORE_ELF_REL_SIZE (output_bfd) < sreloc->size);
 
 
  outrel[0].r_offset =
  outrel[0].r_offset =
    _bfd_elf_section_offset (output_bfd, info, input_section, rel[0].r_offset);
    _bfd_elf_section_offset (output_bfd, info, input_section, rel[0].r_offset);
  outrel[1].r_offset =
  outrel[1].r_offset =
    _bfd_elf_section_offset (output_bfd, info, input_section, rel[1].r_offset);
    _bfd_elf_section_offset (output_bfd, info, input_section, rel[1].r_offset);
  outrel[2].r_offset =
  outrel[2].r_offset =
    _bfd_elf_section_offset (output_bfd, info, input_section, rel[2].r_offset);
    _bfd_elf_section_offset (output_bfd, info, input_section, rel[2].r_offset);
 
 
  if (outrel[0].r_offset == MINUS_ONE)
  if (outrel[0].r_offset == MINUS_ONE)
    /* The relocation field has been deleted.  */
    /* The relocation field has been deleted.  */
    return TRUE;
    return TRUE;
 
 
  if (outrel[0].r_offset == MINUS_TWO)
  if (outrel[0].r_offset == MINUS_TWO)
    {
    {
      /* The relocation field has been converted into a relative value of
      /* The relocation field has been converted into a relative value of
         some sort.  Functions like _bfd_elf_write_section_eh_frame expect
         some sort.  Functions like _bfd_elf_write_section_eh_frame expect
         the field to be fully relocated, so add in the symbol's value.  */
         the field to be fully relocated, so add in the symbol's value.  */
      *addendp += symbol;
      *addendp += symbol;
      return TRUE;
      return TRUE;
    }
    }
 
 
  /* We must now calculate the dynamic symbol table index to use
  /* We must now calculate the dynamic symbol table index to use
     in the relocation.  */
     in the relocation.  */
  if (h != NULL
  if (h != NULL
      && (! info->symbolic || !h->root.def_regular)
      && (! info->symbolic || !h->root.def_regular)
      /* h->root.dynindx may be -1 if this symbol was marked to
      /* h->root.dynindx may be -1 if this symbol was marked to
         become local.  */
         become local.  */
      && h->root.dynindx != -1)
      && h->root.dynindx != -1)
    {
    {
      indx = h->root.dynindx;
      indx = h->root.dynindx;
        /* ??? glibc's ld.so just adds the final GOT entry to the
        /* ??? glibc's ld.so just adds the final GOT entry to the
           relocation field.  It therefore treats relocs against
           relocation field.  It therefore treats relocs against
           defined symbols in the same way as relocs against
           defined symbols in the same way as relocs against
           undefined symbols.  */
           undefined symbols.  */
      defined_p = FALSE;
      defined_p = FALSE;
    }
    }
  else
  else
    {
    {
      indx = 0;
      indx = 0;
      defined_p = TRUE;
      defined_p = TRUE;
    }
    }
 
 
  /* If the relocation was previously an absolute relocation and
  /* If the relocation was previously an absolute relocation and
     this symbol will not be referred to by the relocation, we must
     this symbol will not be referred to by the relocation, we must
     adjust it by the value we give it in the dynamic symbol table.
     adjust it by the value we give it in the dynamic symbol table.
     Otherwise leave the job up to the dynamic linker.  */
     Otherwise leave the job up to the dynamic linker.  */
  if (defined_p && r_type != R_SCORE_REL32)
  if (defined_p && r_type != R_SCORE_REL32)
    *addendp += symbol;
    *addendp += symbol;
 
 
  /* The relocation is always an REL32 relocation because we don't
  /* The relocation is always an REL32 relocation because we don't
     know where the shared library will wind up at load-time.  */
     know where the shared library will wind up at load-time.  */
  outrel[0].r_info = ELF32_R_INFO ((unsigned long) indx, R_SCORE_REL32);
  outrel[0].r_info = ELF32_R_INFO ((unsigned long) indx, R_SCORE_REL32);
 
 
  /* For strict adherence to the ABI specification, we should
  /* For strict adherence to the ABI specification, we should
     generate a R_SCORE_64 relocation record by itself before the
     generate a R_SCORE_64 relocation record by itself before the
     _REL32/_64 record as well, such that the addend is read in as
     _REL32/_64 record as well, such that the addend is read in as
     a 64-bit value (REL32 is a 32-bit relocation, after all).
     a 64-bit value (REL32 is a 32-bit relocation, after all).
     However, since none of the existing ELF64 SCORE dynamic
     However, since none of the existing ELF64 SCORE dynamic
     loaders seems to care, we don't waste space with these
     loaders seems to care, we don't waste space with these
     artificial relocations.  If this turns out to not be true,
     artificial relocations.  If this turns out to not be true,
     score_elf_allocate_dynamic_relocations() should be tweaked so
     score_elf_allocate_dynamic_relocations() should be tweaked so
     as to make room for a pair of dynamic relocations per
     as to make room for a pair of dynamic relocations per
     invocation if ABI_64_P, and here we should generate an
     invocation if ABI_64_P, and here we should generate an
     additional relocation record with R_SCORE_64 by itself for a
     additional relocation record with R_SCORE_64 by itself for a
     NULL symbol before this relocation record.  */
     NULL symbol before this relocation record.  */
  outrel[1].r_info = ELF32_R_INFO (0, R_SCORE_NONE);
  outrel[1].r_info = ELF32_R_INFO (0, R_SCORE_NONE);
  outrel[2].r_info = ELF32_R_INFO (0, R_SCORE_NONE);
  outrel[2].r_info = ELF32_R_INFO (0, R_SCORE_NONE);
 
 
  /* Adjust the output offset of the relocation to reference the
  /* Adjust the output offset of the relocation to reference the
     correct location in the output file.  */
     correct location in the output file.  */
  outrel[0].r_offset += (input_section->output_section->vma
  outrel[0].r_offset += (input_section->output_section->vma
                         + input_section->output_offset);
                         + input_section->output_offset);
  outrel[1].r_offset += (input_section->output_section->vma
  outrel[1].r_offset += (input_section->output_section->vma
                         + input_section->output_offset);
                         + input_section->output_offset);
  outrel[2].r_offset += (input_section->output_section->vma
  outrel[2].r_offset += (input_section->output_section->vma
                         + input_section->output_offset);
                         + input_section->output_offset);
 
 
  /* Put the relocation back out.  We have to use the special
  /* Put the relocation back out.  We have to use the special
     relocation outputter in the 64-bit case since the 64-bit
     relocation outputter in the 64-bit case since the 64-bit
     relocation format is non-standard.  */
     relocation format is non-standard.  */
  bfd_elf32_swap_reloc_out
  bfd_elf32_swap_reloc_out
      (output_bfd, &outrel[0],
      (output_bfd, &outrel[0],
       (sreloc->contents + sreloc->reloc_count * sizeof (Elf32_External_Rel)));
       (sreloc->contents + sreloc->reloc_count * sizeof (Elf32_External_Rel)));
 
 
  /* We've now added another relocation.  */
  /* We've now added another relocation.  */
  ++sreloc->reloc_count;
  ++sreloc->reloc_count;
 
 
  /* Make sure the output section is writable.  The dynamic linker
  /* Make sure the output section is writable.  The dynamic linker
     will be writing to it.  */
     will be writing to it.  */
  elf_section_data (input_section->output_section)->this_hdr.sh_flags |= SHF_WRITE;
  elf_section_data (input_section->output_section)->this_hdr.sh_flags |= SHF_WRITE;
 
 
  return TRUE;
  return TRUE;
}
}
 
 
static bfd_boolean
static bfd_boolean
score_elf_create_got_section (bfd *abfd,
score_elf_create_got_section (bfd *abfd,
                              struct bfd_link_info *info,
                              struct bfd_link_info *info,
                              bfd_boolean maybe_exclude)
                              bfd_boolean maybe_exclude)
{
{
  flagword flags;
  flagword flags;
  asection *s;
  asection *s;
  struct elf_link_hash_entry *h;
  struct elf_link_hash_entry *h;
  struct bfd_link_hash_entry *bh;
  struct bfd_link_hash_entry *bh;
  struct score_got_info *g;
  struct score_got_info *g;
  bfd_size_type amt;
  bfd_size_type amt;
 
 
  /* This function may be called more than once.  */
  /* This function may be called more than once.  */
  s = score_elf_got_section (abfd, TRUE);
  s = score_elf_got_section (abfd, TRUE);
  if (s)
  if (s)
    {
    {
      if (! maybe_exclude)
      if (! maybe_exclude)
        s->flags &= ~SEC_EXCLUDE;
        s->flags &= ~SEC_EXCLUDE;
      return TRUE;
      return TRUE;
    }
    }
 
 
  flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
  flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
 
 
  if (maybe_exclude)
  if (maybe_exclude)
    flags |= SEC_EXCLUDE;
    flags |= SEC_EXCLUDE;
 
 
  /* We have to use an alignment of 2**4 here because this is hardcoded
  /* We have to use an alignment of 2**4 here because this is hardcoded
     in the function stub generation and in the linker script.  */
     in the function stub generation and in the linker script.  */
  s = bfd_make_section_with_flags (abfd, ".got", flags);
  s = bfd_make_section_with_flags (abfd, ".got", flags);
   if (s == NULL
   if (s == NULL
      || ! bfd_set_section_alignment (abfd, s, 4))
      || ! bfd_set_section_alignment (abfd, s, 4))
    return FALSE;
    return FALSE;
 
 
  /* Define the symbol _GLOBAL_OFFSET_TABLE_.  We don't do this in the
  /* Define the symbol _GLOBAL_OFFSET_TABLE_.  We don't do this in the
     linker script because we don't want to define the symbol if we
     linker script because we don't want to define the symbol if we
     are not creating a global offset table.  */
     are not creating a global offset table.  */
  bh = NULL;
  bh = NULL;
  if (! (_bfd_generic_link_add_one_symbol
  if (! (_bfd_generic_link_add_one_symbol
         (info, abfd, "_GLOBAL_OFFSET_TABLE_", BSF_GLOBAL, s,
         (info, abfd, "_GLOBAL_OFFSET_TABLE_", BSF_GLOBAL, s,
          0, NULL, FALSE, get_elf_backend_data (abfd)->collect, &bh)))
          0, NULL, FALSE, get_elf_backend_data (abfd)->collect, &bh)))
    return FALSE;
    return FALSE;
 
 
  h = (struct elf_link_hash_entry *) bh;
  h = (struct elf_link_hash_entry *) bh;
  h->non_elf = 0;
  h->non_elf = 0;
  h->def_regular = 1;
  h->def_regular = 1;
  h->type = STT_OBJECT;
  h->type = STT_OBJECT;
 
 
  if (info->shared && ! bfd_elf_link_record_dynamic_symbol (info, h))
  if (info->shared && ! bfd_elf_link_record_dynamic_symbol (info, h))
    return FALSE;
    return FALSE;
 
 
  amt = sizeof (struct score_got_info);
  amt = sizeof (struct score_got_info);
  g = bfd_alloc (abfd, amt);
  g = bfd_alloc (abfd, amt);
  if (g == NULL)
  if (g == NULL)
    return FALSE;
    return FALSE;
 
 
  g->global_gotsym = NULL;
  g->global_gotsym = NULL;
  g->global_gotno = 0;
  g->global_gotno = 0;
 
 
  g->local_gotno = SCORE_RESERVED_GOTNO;
  g->local_gotno = SCORE_RESERVED_GOTNO;
  g->assigned_gotno = SCORE_RESERVED_GOTNO;
  g->assigned_gotno = SCORE_RESERVED_GOTNO;
  g->next = NULL;
  g->next = NULL;
 
 
  g->got_entries = htab_try_create (1, score_elf_got_entry_hash,
  g->got_entries = htab_try_create (1, score_elf_got_entry_hash,
                                    score_elf_got_entry_eq, NULL);
                                    score_elf_got_entry_eq, NULL);
  if (g->got_entries == NULL)
  if (g->got_entries == NULL)
    return FALSE;
    return FALSE;
  score_elf_section_data (s)->u.got_info = g;
  score_elf_section_data (s)->u.got_info = g;
  score_elf_section_data (s)->elf.this_hdr.sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_SCORE_GPREL;
  score_elf_section_data (s)->elf.this_hdr.sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_SCORE_GPREL;
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* Calculate the %high function.  */
/* Calculate the %high function.  */
static bfd_vma
static bfd_vma
score_elf_high (bfd_vma value)
score_elf_high (bfd_vma value)
{
{
  return ((value + (bfd_vma) 0x8000) >> 16) & 0xffff;
  return ((value + (bfd_vma) 0x8000) >> 16) & 0xffff;
}
}
 
 
/* Create a local GOT entry for VALUE.  Return the index of the entry,
/* Create a local GOT entry for VALUE.  Return the index of the entry,
   or -1 if it could not be created.  */
   or -1 if it could not be created.  */
static struct score_got_entry *
static struct score_got_entry *
score_elf_create_local_got_entry (bfd *abfd,
score_elf_create_local_got_entry (bfd *abfd,
                                  bfd *ibfd ATTRIBUTE_UNUSED,
                                  bfd *ibfd ATTRIBUTE_UNUSED,
                                  struct score_got_info *gg,
                                  struct score_got_info *gg,
                                  asection *sgot, bfd_vma value,
                                  asection *sgot, bfd_vma value,
                                  unsigned long r_symndx ATTRIBUTE_UNUSED,
                                  unsigned long r_symndx ATTRIBUTE_UNUSED,
                                  struct score_elf_link_hash_entry *h ATTRIBUTE_UNUSED,
                                  struct score_elf_link_hash_entry *h ATTRIBUTE_UNUSED,
                                  int r_type ATTRIBUTE_UNUSED)
                                  int r_type ATTRIBUTE_UNUSED)
{
{
  struct score_got_entry entry, **loc;
  struct score_got_entry entry, **loc;
  struct score_got_info *g;
  struct score_got_info *g;
 
 
  entry.abfd = NULL;
  entry.abfd = NULL;
  entry.symndx = -1;
  entry.symndx = -1;
  entry.d.address = value;
  entry.d.address = value;
 
 
  g = gg;
  g = gg;
  loc = (struct score_got_entry **) htab_find_slot (g->got_entries, &entry, INSERT);
  loc = (struct score_got_entry **) htab_find_slot (g->got_entries, &entry, INSERT);
  if (*loc)
  if (*loc)
    return *loc;
    return *loc;
 
 
  entry.gotidx = SCORE_ELF_GOT_SIZE (abfd) * g->assigned_gotno++;
  entry.gotidx = SCORE_ELF_GOT_SIZE (abfd) * g->assigned_gotno++;
 
 
  *loc = bfd_alloc (abfd, sizeof entry);
  *loc = bfd_alloc (abfd, sizeof entry);
 
 
  if (! *loc)
  if (! *loc)
    return NULL;
    return NULL;
 
 
  memcpy (*loc, &entry, sizeof entry);
  memcpy (*loc, &entry, sizeof entry);
 
 
  if (g->assigned_gotno >= g->local_gotno)
  if (g->assigned_gotno >= g->local_gotno)
    {
    {
      (*loc)->gotidx = -1;
      (*loc)->gotidx = -1;
      /* We didn't allocate enough space in the GOT.  */
      /* We didn't allocate enough space in the GOT.  */
      (*_bfd_error_handler)
      (*_bfd_error_handler)
        (_("not enough GOT space for local GOT entries"));
        (_("not enough GOT space for local GOT entries"));
      bfd_set_error (bfd_error_bad_value);
      bfd_set_error (bfd_error_bad_value);
      return NULL;
      return NULL;
    }
    }
 
 
  score_bfd_put_32 (abfd, value, (sgot->contents + entry.gotidx));
  score_bfd_put_32 (abfd, value, (sgot->contents + entry.gotidx));
 
 
  return *loc;
  return *loc;
}
}
 
 
/* Find a GOT entry whose higher-order 16 bits are the same as those
/* Find a GOT entry whose higher-order 16 bits are the same as those
   for value.  Return the index into the GOT for this entry.  */
   for value.  Return the index into the GOT for this entry.  */
static bfd_vma
static bfd_vma
score_elf_got16_entry (bfd *abfd, bfd *ibfd, struct bfd_link_info *info,
score_elf_got16_entry (bfd *abfd, bfd *ibfd, struct bfd_link_info *info,
                       bfd_vma value, bfd_boolean external)
                       bfd_vma value, bfd_boolean external)
{
{
  asection *sgot;
  asection *sgot;
  struct score_got_info *g;
  struct score_got_info *g;
  struct score_got_entry *entry;
  struct score_got_entry *entry;
 
 
  if (!external)
  if (!external)
    {
    {
      /* Although the ABI says that it is "the high-order 16 bits" that we
      /* Although the ABI says that it is "the high-order 16 bits" that we
         want, it is really the %high value.  The complete value is
         want, it is really the %high value.  The complete value is
         calculated with a `addiu' of a LO16 relocation, just as with a
         calculated with a `addiu' of a LO16 relocation, just as with a
         HI16/LO16 pair.  */
         HI16/LO16 pair.  */
      value = score_elf_high (value) << 16;
      value = score_elf_high (value) << 16;
    }
    }
 
 
  g = score_elf_got_info (elf_hash_table (info)->dynobj, &sgot);
  g = score_elf_got_info (elf_hash_table (info)->dynobj, &sgot);
 
 
  entry = score_elf_create_local_got_entry (abfd, ibfd, g, sgot, value, 0, NULL,
  entry = score_elf_create_local_got_entry (abfd, ibfd, g, sgot, value, 0, NULL,
                                            R_SCORE_GOT15);
                                            R_SCORE_GOT15);
  if (entry)
  if (entry)
    return entry->gotidx;
    return entry->gotidx;
  else
  else
    return MINUS_ONE;
    return MINUS_ONE;
}
}
 
 
static void
static void
s3_bfd_score_elf_hide_symbol (struct bfd_link_info *info,
s3_bfd_score_elf_hide_symbol (struct bfd_link_info *info,
                              struct elf_link_hash_entry *entry,
                              struct elf_link_hash_entry *entry,
                              bfd_boolean force_local)
                              bfd_boolean force_local)
{
{
  bfd *dynobj;
  bfd *dynobj;
  asection *got;
  asection *got;
  struct score_got_info *g;
  struct score_got_info *g;
  struct score_elf_link_hash_entry *h;
  struct score_elf_link_hash_entry *h;
 
 
  h = (struct score_elf_link_hash_entry *) entry;
  h = (struct score_elf_link_hash_entry *) entry;
  if (h->forced_local)
  if (h->forced_local)
    return;
    return;
  h->forced_local = TRUE;
  h->forced_local = TRUE;
 
 
  dynobj = elf_hash_table (info)->dynobj;
  dynobj = elf_hash_table (info)->dynobj;
  if (dynobj != NULL && force_local)
  if (dynobj != NULL && force_local)
    {
    {
      got = score_elf_got_section (dynobj, FALSE);
      got = score_elf_got_section (dynobj, FALSE);
      if (got == NULL)
      if (got == NULL)
        return;
        return;
      g = score_elf_section_data (got)->u.got_info;
      g = score_elf_section_data (got)->u.got_info;
 
 
      if (g->next)
      if (g->next)
        {
        {
          struct score_got_entry e;
          struct score_got_entry e;
          struct score_got_info *gg = g;
          struct score_got_info *gg = g;
 
 
          /* Since we're turning what used to be a global symbol into a
          /* Since we're turning what used to be a global symbol into a
             local one, bump up the number of local entries of each GOT
             local one, bump up the number of local entries of each GOT
             that had an entry for it.  This will automatically decrease
             that had an entry for it.  This will automatically decrease
             the number of global entries, since global_gotno is actually
             the number of global entries, since global_gotno is actually
             the upper limit of global entries.  */
             the upper limit of global entries.  */
          e.abfd = dynobj;
          e.abfd = dynobj;
          e.symndx = -1;
          e.symndx = -1;
          e.d.h = h;
          e.d.h = h;
 
 
          for (g = g->next; g != gg; g = g->next)
          for (g = g->next; g != gg; g = g->next)
            if (htab_find (g->got_entries, &e))
            if (htab_find (g->got_entries, &e))
              {
              {
                BFD_ASSERT (g->global_gotno > 0);
                BFD_ASSERT (g->global_gotno > 0);
                g->local_gotno++;
                g->local_gotno++;
                g->global_gotno--;
                g->global_gotno--;
              }
              }
 
 
          /* If this was a global symbol forced into the primary GOT, we
          /* If this was a global symbol forced into the primary GOT, we
             no longer need an entry for it.  We can't release the entry
             no longer need an entry for it.  We can't release the entry
             at this point, but we must at least stop counting it as one
             at this point, but we must at least stop counting it as one
             of the symbols that required a forced got entry.  */
             of the symbols that required a forced got entry.  */
          if (h->root.got.offset == 2)
          if (h->root.got.offset == 2)
            {
            {
              BFD_ASSERT (gg->assigned_gotno > 0);
              BFD_ASSERT (gg->assigned_gotno > 0);
              gg->assigned_gotno--;
              gg->assigned_gotno--;
            }
            }
        }
        }
      else if (g->global_gotno == 0 && g->global_gotsym == NULL)
      else if (g->global_gotno == 0 && g->global_gotsym == NULL)
        /* If we haven't got through GOT allocation yet, just bump up the
        /* If we haven't got through GOT allocation yet, just bump up the
              number of local entries, as this symbol won't be counted as
              number of local entries, as this symbol won't be counted as
              global.  */
              global.  */
        g->local_gotno++;
        g->local_gotno++;
      else if (h->root.got.offset == 1)
      else if (h->root.got.offset == 1)
        {
        {
          /* If we're past non-multi-GOT allocation and this symbol had
          /* If we're past non-multi-GOT allocation and this symbol had
                  been marked for a global got entry, give it a local entry
                  been marked for a global got entry, give it a local entry
                  instead.  */
                  instead.  */
          BFD_ASSERT (g->global_gotno > 0);
          BFD_ASSERT (g->global_gotno > 0);
          g->local_gotno++;
          g->local_gotno++;
          g->global_gotno--;
          g->global_gotno--;
        }
        }
    }
    }
 
 
  _bfd_elf_link_hash_hide_symbol (info, &h->root, force_local);
  _bfd_elf_link_hash_hide_symbol (info, &h->root, force_local);
}
}
 
 
/* If H is a symbol that needs a global GOT entry, but has a dynamic
/* If H is a symbol that needs a global GOT entry, but has a dynamic
   symbol table index lower than any we've seen to date, record it for
   symbol table index lower than any we've seen to date, record it for
   posterity.  */
   posterity.  */
static bfd_boolean
static bfd_boolean
score_elf_record_global_got_symbol (struct elf_link_hash_entry *h,
score_elf_record_global_got_symbol (struct elf_link_hash_entry *h,
                                    bfd *abfd,
                                    bfd *abfd,
                                    struct bfd_link_info *info,
                                    struct bfd_link_info *info,
                                    struct score_got_info *g)
                                    struct score_got_info *g)
{
{
  struct score_got_entry entry, **loc;
  struct score_got_entry entry, **loc;
 
 
  /* A global symbol in the GOT must also be in the dynamic symbol table.  */
  /* A global symbol in the GOT must also be in the dynamic symbol table.  */
  if (h->dynindx == -1)
  if (h->dynindx == -1)
    {
    {
      switch (ELF_ST_VISIBILITY (h->other))
      switch (ELF_ST_VISIBILITY (h->other))
        {
        {
        case STV_INTERNAL:
        case STV_INTERNAL:
        case STV_HIDDEN:
        case STV_HIDDEN:
          s3_bfd_score_elf_hide_symbol (info, h, TRUE);
          s3_bfd_score_elf_hide_symbol (info, h, TRUE);
          break;
          break;
        }
        }
      if (!bfd_elf_link_record_dynamic_symbol (info, h))
      if (!bfd_elf_link_record_dynamic_symbol (info, h))
        return FALSE;
        return FALSE;
    }
    }
 
 
  entry.abfd = abfd;
  entry.abfd = abfd;
  entry.symndx = -1;
  entry.symndx = -1;
  entry.d.h = (struct score_elf_link_hash_entry *)h;
  entry.d.h = (struct score_elf_link_hash_entry *)h;
 
 
  loc = (struct score_got_entry **)htab_find_slot (g->got_entries, &entry, INSERT);
  loc = (struct score_got_entry **)htab_find_slot (g->got_entries, &entry, INSERT);
 
 
  /* If we've already marked this entry as needing GOT space, we don't
  /* If we've already marked this entry as needing GOT space, we don't
     need to do it again.  */
     need to do it again.  */
  if (*loc)
  if (*loc)
    return TRUE;
    return TRUE;
 
 
  *loc = bfd_alloc (abfd, sizeof entry);
  *loc = bfd_alloc (abfd, sizeof entry);
  if (! *loc)
  if (! *loc)
    return FALSE;
    return FALSE;
 
 
  entry.gotidx = -1;
  entry.gotidx = -1;
 
 
  memcpy (*loc, &entry, sizeof (entry));
  memcpy (*loc, &entry, sizeof (entry));
 
 
  if (h->got.offset != MINUS_ONE)
  if (h->got.offset != MINUS_ONE)
    return TRUE;
    return TRUE;
 
 
  /* By setting this to a value other than -1, we are indicating that
  /* By setting this to a value other than -1, we are indicating that
     there needs to be a GOT entry for H.  Avoid using zero, as the
     there needs to be a GOT entry for H.  Avoid using zero, as the
     generic ELF copy_indirect_symbol tests for <= 0.  */
     generic ELF copy_indirect_symbol tests for <= 0.  */
  h->got.offset = 1;
  h->got.offset = 1;
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* Reserve space in G for a GOT entry containing the value of symbol
/* Reserve space in G for a GOT entry containing the value of symbol
   SYMNDX in input bfd ABDF, plus ADDEND.  */
   SYMNDX in input bfd ABDF, plus ADDEND.  */
static bfd_boolean
static bfd_boolean
score_elf_record_local_got_symbol (bfd *abfd,
score_elf_record_local_got_symbol (bfd *abfd,
                                   long symndx,
                                   long symndx,
                                   bfd_vma addend,
                                   bfd_vma addend,
                                   struct score_got_info *g)
                                   struct score_got_info *g)
{
{
  struct score_got_entry entry, **loc;
  struct score_got_entry entry, **loc;
 
 
  entry.abfd = abfd;
  entry.abfd = abfd;
  entry.symndx = symndx;
  entry.symndx = symndx;
  entry.d.addend = addend;
  entry.d.addend = addend;
  loc = (struct score_got_entry **)htab_find_slot (g->got_entries, &entry, INSERT);
  loc = (struct score_got_entry **)htab_find_slot (g->got_entries, &entry, INSERT);
 
 
  if (*loc)
  if (*loc)
    return TRUE;
    return TRUE;
 
 
  entry.gotidx = g->local_gotno++;
  entry.gotidx = g->local_gotno++;
 
 
  *loc = bfd_alloc (abfd, sizeof(entry));
  *loc = bfd_alloc (abfd, sizeof(entry));
  if (! *loc)
  if (! *loc)
    return FALSE;
    return FALSE;
 
 
  memcpy (*loc, &entry, sizeof (entry));
  memcpy (*loc, &entry, sizeof (entry));
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* Returns the GOT offset at which the indicated address can be found.
/* Returns the GOT offset at which the indicated address can be found.
   If there is not yet a GOT entry for this value, create one.
   If there is not yet a GOT entry for this value, create one.
   Returns -1 if no satisfactory GOT offset can be found.  */
   Returns -1 if no satisfactory GOT offset can be found.  */
static bfd_vma
static bfd_vma
score_elf_local_got_index (bfd *abfd, bfd *ibfd, struct bfd_link_info *info,
score_elf_local_got_index (bfd *abfd, bfd *ibfd, struct bfd_link_info *info,
                           bfd_vma value, unsigned long r_symndx,
                           bfd_vma value, unsigned long r_symndx,
                           struct score_elf_link_hash_entry *h, int r_type)
                           struct score_elf_link_hash_entry *h, int r_type)
{
{
  asection *sgot;
  asection *sgot;
  struct score_got_info *g;
  struct score_got_info *g;
  struct score_got_entry *entry;
  struct score_got_entry *entry;
 
 
  g = score_elf_got_info (elf_hash_table (info)->dynobj, &sgot);
  g = score_elf_got_info (elf_hash_table (info)->dynobj, &sgot);
 
 
  entry = score_elf_create_local_got_entry (abfd, ibfd, g, sgot, value,
  entry = score_elf_create_local_got_entry (abfd, ibfd, g, sgot, value,
                                             r_symndx, h, r_type);
                                             r_symndx, h, r_type);
  if (!entry)
  if (!entry)
    return MINUS_ONE;
    return MINUS_ONE;
 
 
  else
  else
    return entry->gotidx;
    return entry->gotidx;
}
}
 
 
/* Returns the GOT index for the global symbol indicated by H.  */
/* Returns the GOT index for the global symbol indicated by H.  */
 
 
static bfd_vma
static bfd_vma
score_elf_global_got_index (bfd *abfd, struct elf_link_hash_entry *h)
score_elf_global_got_index (bfd *abfd, struct elf_link_hash_entry *h)
{
{
  bfd_vma got_index;
  bfd_vma got_index;
  asection *sgot;
  asection *sgot;
  struct score_got_info *g;
  struct score_got_info *g;
  long global_got_dynindx = 0;
  long global_got_dynindx = 0;
 
 
  g = score_elf_got_info (abfd, &sgot);
  g = score_elf_got_info (abfd, &sgot);
  if (g->global_gotsym != NULL)
  if (g->global_gotsym != NULL)
    global_got_dynindx = g->global_gotsym->dynindx;
    global_got_dynindx = g->global_gotsym->dynindx;
 
 
  /* Once we determine the global GOT entry with the lowest dynamic
  /* Once we determine the global GOT entry with the lowest dynamic
     symbol table index, we must put all dynamic symbols with greater
     symbol table index, we must put all dynamic symbols with greater
     indices into the GOT.  That makes it easy to calculate the GOT
     indices into the GOT.  That makes it easy to calculate the GOT
     offset.  */
     offset.  */
  BFD_ASSERT (h->dynindx >= global_got_dynindx);
  BFD_ASSERT (h->dynindx >= global_got_dynindx);
  got_index = ((h->dynindx - global_got_dynindx + g->local_gotno) * SCORE_ELF_GOT_SIZE (abfd));
  got_index = ((h->dynindx - global_got_dynindx + g->local_gotno) * SCORE_ELF_GOT_SIZE (abfd));
  BFD_ASSERT (got_index < sgot->size);
  BFD_ASSERT (got_index < sgot->size);
 
 
  return got_index;
  return got_index;
}
}
 
 
/* Returns the offset for the entry at the INDEXth position in the GOT.  */
/* Returns the offset for the entry at the INDEXth position in the GOT.  */
 
 
static bfd_vma
static bfd_vma
score_elf_got_offset_from_index (bfd *dynobj,
score_elf_got_offset_from_index (bfd *dynobj,
                                 bfd *output_bfd,
                                 bfd *output_bfd,
                                 bfd *input_bfd ATTRIBUTE_UNUSED,
                                 bfd *input_bfd ATTRIBUTE_UNUSED,
                                 bfd_vma got_index)
                                 bfd_vma got_index)
{
{
  asection *sgot;
  asection *sgot;
  bfd_vma gp;
  bfd_vma gp;
  struct score_got_info *g;
  struct score_got_info *g;
 
 
  g = score_elf_got_info (dynobj, &sgot);
  g = score_elf_got_info (dynobj, &sgot);
  gp = _bfd_get_gp_value (output_bfd);
  gp = _bfd_get_gp_value (output_bfd);
 
 
  return sgot->output_section->vma + sgot->output_offset + got_index - gp;
  return sgot->output_section->vma + sgot->output_offset + got_index - gp;
}
}
 
 
/* Follow indirect and warning hash entries so that each got entry
/* Follow indirect and warning hash entries so that each got entry
   points to the final symbol definition.  P must point to a pointer
   points to the final symbol definition.  P must point to a pointer
   to the hash table we're traversing.  Since this traversal may
   to the hash table we're traversing.  Since this traversal may
   modify the hash table, we set this pointer to NULL to indicate
   modify the hash table, we set this pointer to NULL to indicate
   we've made a potentially-destructive change to the hash table, so
   we've made a potentially-destructive change to the hash table, so
   the traversal must be restarted.  */
   the traversal must be restarted.  */
static int
static int
score_elf_resolve_final_got_entry (void **entryp, void *p)
score_elf_resolve_final_got_entry (void **entryp, void *p)
{
{
  struct score_got_entry *entry = (struct score_got_entry *)*entryp;
  struct score_got_entry *entry = (struct score_got_entry *)*entryp;
  htab_t got_entries = *(htab_t *)p;
  htab_t got_entries = *(htab_t *)p;
 
 
  if (entry->abfd != NULL && entry->symndx == -1)
  if (entry->abfd != NULL && entry->symndx == -1)
    {
    {
      struct score_elf_link_hash_entry *h = entry->d.h;
      struct score_elf_link_hash_entry *h = entry->d.h;
 
 
      while (h->root.root.type == bfd_link_hash_indirect
      while (h->root.root.type == bfd_link_hash_indirect
             || h->root.root.type == bfd_link_hash_warning)
             || h->root.root.type == bfd_link_hash_warning)
        h = (struct score_elf_link_hash_entry *) h->root.root.u.i.link;
        h = (struct score_elf_link_hash_entry *) h->root.root.u.i.link;
 
 
      if (entry->d.h == h)
      if (entry->d.h == h)
        return 1;
        return 1;
 
 
      entry->d.h = h;
      entry->d.h = h;
 
 
      /* If we can't find this entry with the new bfd hash, re-insert
      /* If we can't find this entry with the new bfd hash, re-insert
         it, and get the traversal restarted.  */
         it, and get the traversal restarted.  */
      if (! htab_find (got_entries, entry))
      if (! htab_find (got_entries, entry))
        {
        {
          htab_clear_slot (got_entries, entryp);
          htab_clear_slot (got_entries, entryp);
          entryp = htab_find_slot (got_entries, entry, INSERT);
          entryp = htab_find_slot (got_entries, entry, INSERT);
          if (! *entryp)
          if (! *entryp)
            *entryp = entry;
            *entryp = entry;
          /* Abort the traversal, since the whole table may have
          /* Abort the traversal, since the whole table may have
             moved, and leave it up to the parent to restart the
             moved, and leave it up to the parent to restart the
             process.  */
             process.  */
          *(htab_t *)p = NULL;
          *(htab_t *)p = NULL;
          return 0;
          return 0;
        }
        }
      /* We might want to decrement the global_gotno count, but it's
      /* We might want to decrement the global_gotno count, but it's
         either too early or too late for that at this point.  */
         either too early or too late for that at this point.  */
    }
    }
 
 
  return 1;
  return 1;
}
}
 
 
/* Turn indirect got entries in a got_entries table into their final locations.  */
/* Turn indirect got entries in a got_entries table into their final locations.  */
static void
static void
score_elf_resolve_final_got_entries (struct score_got_info *g)
score_elf_resolve_final_got_entries (struct score_got_info *g)
{
{
  htab_t got_entries;
  htab_t got_entries;
 
 
  do
  do
    {
    {
      got_entries = g->got_entries;
      got_entries = g->got_entries;
 
 
      htab_traverse (got_entries,
      htab_traverse (got_entries,
                     score_elf_resolve_final_got_entry,
                     score_elf_resolve_final_got_entry,
                     &got_entries);
                     &got_entries);
    }
    }
  while (got_entries == NULL);
  while (got_entries == NULL);
}
}
 
 
/* Add INCREMENT to the reloc (of type HOWTO) at ADDRESS. for -r  */
/* Add INCREMENT to the reloc (of type HOWTO) at ADDRESS. for -r  */
static void
static void
score_elf_add_to_rel (bfd *abfd,
score_elf_add_to_rel (bfd *abfd,
                      bfd_byte *address,
                      bfd_byte *address,
                      reloc_howto_type *howto,
                      reloc_howto_type *howto,
                      bfd_signed_vma increment)
                      bfd_signed_vma increment)
{
{
  bfd_signed_vma addend;
  bfd_signed_vma addend;
  bfd_vma contents;
  bfd_vma contents;
  unsigned long offset;
  unsigned long offset;
  unsigned long r_type = howto->type;
  unsigned long r_type = howto->type;
  unsigned long hi16_addend, hi16_offset, hi16_value, uvalue;
  unsigned long hi16_addend, hi16_offset, hi16_value, uvalue;
 
 
  contents = score_bfd_get_32 (abfd, address);
  contents = score_bfd_get_32 (abfd, address);
  /* Get the (signed) value from the instruction.  */
  /* Get the (signed) value from the instruction.  */
  addend = contents & howto->src_mask;
  addend = contents & howto->src_mask;
  if (addend & ((howto->src_mask + 1) >> 1))
  if (addend & ((howto->src_mask + 1) >> 1))
    {
    {
      bfd_signed_vma mask;
      bfd_signed_vma mask;
 
 
      mask = -1;
      mask = -1;
      mask &= ~howto->src_mask;
      mask &= ~howto->src_mask;
      addend |= mask;
      addend |= mask;
    }
    }
  /* Add in the increment, (which is a byte value).  */
  /* Add in the increment, (which is a byte value).  */
  switch (r_type)
  switch (r_type)
    {
    {
    case R_SCORE_PC19:
    case R_SCORE_PC19:
      offset =
      offset =
        (((contents & howto->src_mask) & 0x3ff0000) >> 6) | ((contents & howto->src_mask) & 0x3ff);
        (((contents & howto->src_mask) & 0x3ff0000) >> 6) | ((contents & howto->src_mask) & 0x3ff);
      offset += increment;
      offset += increment;
      contents =
      contents =
        (contents & ~howto->
        (contents & ~howto->
         src_mask) | (((offset << 6) & howto->src_mask) & 0x3ff0000) | (offset & 0x3ff);
         src_mask) | (((offset << 6) & howto->src_mask) & 0x3ff0000) | (offset & 0x3ff);
      score_bfd_put_32 (abfd, contents, address);
      score_bfd_put_32 (abfd, contents, address);
      break;
      break;
    case R_SCORE_HI16:
    case R_SCORE_HI16:
      break;
      break;
    case R_SCORE_LO16:
    case R_SCORE_LO16:
      hi16_addend = score_bfd_get_32 (abfd, address - 4);
      hi16_addend = score_bfd_get_32 (abfd, address - 4);
      hi16_offset = ((((hi16_addend >> 16) & 0x3) << 15) | (hi16_addend & 0x7fff)) >> 1;
      hi16_offset = ((((hi16_addend >> 16) & 0x3) << 15) | (hi16_addend & 0x7fff)) >> 1;
      offset = ((((contents >> 16) & 0x3) << 15) | (contents & 0x7fff)) >> 1;
      offset = ((((contents >> 16) & 0x3) << 15) | (contents & 0x7fff)) >> 1;
      offset = (hi16_offset << 16) | (offset & 0xffff);
      offset = (hi16_offset << 16) | (offset & 0xffff);
      uvalue = increment + offset;
      uvalue = increment + offset;
      hi16_offset = (uvalue >> 16) << 1;
      hi16_offset = (uvalue >> 16) << 1;
      hi16_value = (hi16_addend & (~(howto->dst_mask)))
      hi16_value = (hi16_addend & (~(howto->dst_mask)))
        | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000);
        | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000);
      score_bfd_put_32 (abfd, hi16_value, address - 4);
      score_bfd_put_32 (abfd, hi16_value, address - 4);
      offset = (uvalue & 0xffff) << 1;
      offset = (uvalue & 0xffff) << 1;
      contents = (contents & (~(howto->dst_mask))) | (offset & 0x7fff) | ((offset << 1) & 0x30000);
      contents = (contents & (~(howto->dst_mask))) | (offset & 0x7fff) | ((offset << 1) & 0x30000);
      score_bfd_put_32 (abfd, contents, address);
      score_bfd_put_32 (abfd, contents, address);
      break;
      break;
    case R_SCORE_24:
    case R_SCORE_24:
      offset =
      offset =
        (((contents & howto->src_mask) >> 1) & 0x1ff8000) | ((contents & howto->src_mask) & 0x7fff);
        (((contents & howto->src_mask) >> 1) & 0x1ff8000) | ((contents & howto->src_mask) & 0x7fff);
      offset += increment;
      offset += increment;
      contents =
      contents =
        (contents & ~howto->
        (contents & ~howto->
         src_mask) | (((offset << 1) & howto->src_mask) & 0x3ff0000) | (offset & 0x7fff);
         src_mask) | (((offset << 1) & howto->src_mask) & 0x3ff0000) | (offset & 0x7fff);
      score_bfd_put_32 (abfd, contents, address);
      score_bfd_put_32 (abfd, contents, address);
      break;
      break;
 
 
    case R_SCORE16_11:
    case R_SCORE16_11:
 
 
      contents = score_bfd_get_16 (abfd, address);
      contents = score_bfd_get_16 (abfd, address);
      offset = contents & howto->src_mask;
      offset = contents & howto->src_mask;
      offset += increment;
      offset += increment;
      contents = (contents & ~howto->src_mask) | (offset & howto->src_mask);
      contents = (contents & ~howto->src_mask) | (offset & howto->src_mask);
      score_bfd_put_16 (abfd, contents, address);
      score_bfd_put_16 (abfd, contents, address);
 
 
      break;
      break;
    case R_SCORE16_PC8:
    case R_SCORE16_PC8:
 
 
      contents = score_bfd_get_16 (abfd, address);
      contents = score_bfd_get_16 (abfd, address);
      offset = (contents & howto->src_mask) + ((increment >> 1) & 0x1ff);
      offset = (contents & howto->src_mask) + ((increment >> 1) & 0x1ff);
      contents = (contents & (~howto->src_mask)) | (offset & howto->src_mask);
      contents = (contents & (~howto->src_mask)) | (offset & howto->src_mask);
      score_bfd_put_16 (abfd, contents, address);
      score_bfd_put_16 (abfd, contents, address);
 
 
      break;
      break;
 
 
    case R_SCORE_BCMP:
    case R_SCORE_BCMP:
      contents = score_bfd_get_32 (abfd, address);
      contents = score_bfd_get_32 (abfd, address);
      offset = (contents & howto->src_mask);
      offset = (contents & howto->src_mask);
      offset <<= howto->rightshift;
      offset <<= howto->rightshift;
      offset += increment;
      offset += increment;
      offset >>= howto->rightshift;
      offset >>= howto->rightshift;
      contents = (contents & (~howto->src_mask)) | (offset & howto->src_mask);
      contents = (contents & (~howto->src_mask)) | (offset & howto->src_mask);
      score_bfd_put_32 (abfd, contents, address);
      score_bfd_put_32 (abfd, contents, address);
      break;
      break;
 
 
    case R_SCORE_IMM30:
    case R_SCORE_IMM30:
      contents = score_bfd_get_48 (abfd, address);
      contents = score_bfd_get_48 (abfd, address);
      offset = (contents & howto->src_mask);
      offset = (contents & howto->src_mask);
      offset <<= howto->rightshift;
      offset <<= howto->rightshift;
      offset += increment;
      offset += increment;
      offset >>= howto->rightshift;
      offset >>= howto->rightshift;
      contents = (contents & (~howto->src_mask)) | (offset & howto->src_mask);
      contents = (contents & (~howto->src_mask)) | (offset & howto->src_mask);
      score_bfd_put_48 (abfd, contents, address);
      score_bfd_put_48 (abfd, contents, address);
      break;
      break;
 
 
    case R_SCORE_IMM32:
    case R_SCORE_IMM32:
      contents = score_bfd_get_48 (abfd, address);
      contents = score_bfd_get_48 (abfd, address);
      offset = (contents & howto->src_mask);
      offset = (contents & howto->src_mask);
      offset += increment;
      offset += increment;
      contents = (contents & (~howto->src_mask)) | (offset & howto->src_mask);
      contents = (contents & (~howto->src_mask)) | (offset & howto->src_mask);
      score_bfd_put_48 (abfd, contents, address);
      score_bfd_put_48 (abfd, contents, address);
      break;
      break;
 
 
    default:
    default:
      addend += increment;
      addend += increment;
      contents = (contents & ~howto->dst_mask) | (addend & howto->dst_mask);
      contents = (contents & ~howto->dst_mask) | (addend & howto->dst_mask);
      score_bfd_put_32 (abfd, contents, address);
      score_bfd_put_32 (abfd, contents, address);
      break;
      break;
    }
    }
}
}
 
 
/* Perform a relocation as part of a final link.  */
/* Perform a relocation as part of a final link.  */
static bfd_reloc_status_type
static bfd_reloc_status_type
score_elf_final_link_relocate (reloc_howto_type *howto,
score_elf_final_link_relocate (reloc_howto_type *howto,
                               bfd *input_bfd,
                               bfd *input_bfd,
                               bfd *output_bfd,
                               bfd *output_bfd,
                               asection *input_section,
                               asection *input_section,
                               bfd_byte *contents,
                               bfd_byte *contents,
                               Elf_Internal_Rela *rel,
                               Elf_Internal_Rela *rel,
                               Elf_Internal_Rela *relocs,
                               Elf_Internal_Rela *relocs,
                               bfd_vma symbol,
                               bfd_vma symbol,
                               struct bfd_link_info *info,
                               struct bfd_link_info *info,
                               const char *sym_name ATTRIBUTE_UNUSED,
                               const char *sym_name ATTRIBUTE_UNUSED,
                               int sym_flags ATTRIBUTE_UNUSED,
                               int sym_flags ATTRIBUTE_UNUSED,
                               struct score_elf_link_hash_entry *h,
                               struct score_elf_link_hash_entry *h,
                               asection **local_sections,
                               asection **local_sections,
                               bfd_boolean gp_disp_p)
                               bfd_boolean gp_disp_p)
{
{
  unsigned long r_type;
  unsigned long r_type;
  unsigned long r_symndx;
  unsigned long r_symndx;
  bfd_byte *hit_data = contents + rel->r_offset;
  bfd_byte *hit_data = contents + rel->r_offset;
  bfd_vma addend;
  bfd_vma addend;
  /* The final GP value to be used for the relocatable, executable, or
  /* The final GP value to be used for the relocatable, executable, or
     shared object file being produced.  */
     shared object file being produced.  */
  bfd_vma gp = MINUS_ONE;
  bfd_vma gp = MINUS_ONE;
  /* The place (section offset or address) of the storage unit being relocated.  */
  /* The place (section offset or address) of the storage unit being relocated.  */
  bfd_vma rel_addr;
  bfd_vma rel_addr;
  /* The value of GP used to create the relocatable object.  */
  /* The value of GP used to create the relocatable object.  */
  bfd_vma gp0 = MINUS_ONE;
  bfd_vma gp0 = MINUS_ONE;
  /* The offset into the global offset table at which the address of the relocation entry
  /* The offset into the global offset table at which the address of the relocation entry
     symbol, adjusted by the addend, resides during execution.  */
     symbol, adjusted by the addend, resides during execution.  */
  bfd_vma g = MINUS_ONE;
  bfd_vma g = MINUS_ONE;
  /* TRUE if the symbol referred to by this relocation is a local symbol.  */
  /* TRUE if the symbol referred to by this relocation is a local symbol.  */
  bfd_boolean local_p;
  bfd_boolean local_p;
  /* The eventual value we will relocate.  */
  /* The eventual value we will relocate.  */
  bfd_vma value = symbol;
  bfd_vma value = symbol;
  unsigned long hi16_addend, hi16_offset, hi16_value, uvalue, offset, abs_value = 0;
  unsigned long hi16_addend, hi16_offset, hi16_value, uvalue, offset, abs_value = 0;
 
 
 
 
  if (elf_gp (output_bfd) == 0)
  if (elf_gp (output_bfd) == 0)
    {
    {
      struct bfd_link_hash_entry *bh;
      struct bfd_link_hash_entry *bh;
      asection *o;
      asection *o;
 
 
      bh = bfd_link_hash_lookup (info->hash, "_gp", 0, 0, 1);
      bh = bfd_link_hash_lookup (info->hash, "_gp", 0, 0, 1);
      if (bh != NULL && bh->type == bfd_link_hash_defined)
      if (bh != NULL && bh->type == bfd_link_hash_defined)
        elf_gp (output_bfd) = (bh->u.def.value
        elf_gp (output_bfd) = (bh->u.def.value
                               + bh->u.def.section->output_section->vma
                               + bh->u.def.section->output_section->vma
                               + bh->u.def.section->output_offset);
                               + bh->u.def.section->output_offset);
      else if (info->relocatable)
      else if (info->relocatable)
        {
        {
          bfd_vma lo = -1;
          bfd_vma lo = -1;
 
 
          /* Find the GP-relative section with the lowest offset.  */
          /* Find the GP-relative section with the lowest offset.  */
          for (o = output_bfd->sections; o != NULL; o = o->next)
          for (o = output_bfd->sections; o != NULL; o = o->next)
            if (o->vma < lo)
            if (o->vma < lo)
              lo = o->vma;
              lo = o->vma;
          /* And calculate GP relative to that.  */
          /* And calculate GP relative to that.  */
          elf_gp (output_bfd) = lo + ELF_SCORE_GP_OFFSET (input_bfd);
          elf_gp (output_bfd) = lo + ELF_SCORE_GP_OFFSET (input_bfd);
        }
        }
      else
      else
        {
        {
          /* If the relocate_section function needs to do a reloc
          /* If the relocate_section function needs to do a reloc
             involving the GP value, it should make a reloc_dangerous
             involving the GP value, it should make a reloc_dangerous
             callback to warn that GP is not defined.  */
             callback to warn that GP is not defined.  */
        }
        }
    }
    }
 
 
  /* Parse the relocation.  */
  /* Parse the relocation.  */
  r_symndx = ELF32_R_SYM (rel->r_info);
  r_symndx = ELF32_R_SYM (rel->r_info);
  r_type = ELF32_R_TYPE (rel->r_info);
  r_type = ELF32_R_TYPE (rel->r_info);
  rel_addr = (input_section->output_section->vma + input_section->output_offset + rel->r_offset);
  rel_addr = (input_section->output_section->vma + input_section->output_offset + rel->r_offset);
  local_p = score_elf_local_relocation_p (input_bfd, rel, local_sections, TRUE);
  local_p = score_elf_local_relocation_p (input_bfd, rel, local_sections, TRUE);
 
 
  if (r_type == R_SCORE_GOT15)
  if (r_type == R_SCORE_GOT15)
    {
    {
      const Elf_Internal_Rela *relend;
      const Elf_Internal_Rela *relend;
      const Elf_Internal_Rela *lo16_rel;
      const Elf_Internal_Rela *lo16_rel;
      const struct elf_backend_data *bed;
      const struct elf_backend_data *bed;
      bfd_vma lo_value = 0;
      bfd_vma lo_value = 0;
 
 
      bed = get_elf_backend_data (output_bfd);
      bed = get_elf_backend_data (output_bfd);
      relend = relocs + input_section->reloc_count * bed->s->int_rels_per_ext_rel;
      relend = relocs + input_section->reloc_count * bed->s->int_rels_per_ext_rel;
      lo16_rel = score_elf_next_relocation (input_bfd, R_SCORE_GOT_LO16, rel, relend);
      lo16_rel = score_elf_next_relocation (input_bfd, R_SCORE_GOT_LO16, rel, relend);
      if ((local_p) && (lo16_rel != NULL))
      if ((local_p) && (lo16_rel != NULL))
        {
        {
          bfd_vma tmp = 0;
          bfd_vma tmp = 0;
          tmp = score_bfd_get_32 (input_bfd, contents + lo16_rel->r_offset);
          tmp = score_bfd_get_32 (input_bfd, contents + lo16_rel->r_offset);
          lo_value = (((tmp >> 16) & 0x3) << 14) | ((tmp & 0x7fff) >> 1);
          lo_value = (((tmp >> 16) & 0x3) << 14) | ((tmp & 0x7fff) >> 1);
        }
        }
      addend = lo_value;
      addend = lo_value;
    }
    }
  /* For score3 R_SCORE_ABS32.  */
  /* For score3 R_SCORE_ABS32.  */
  else if (r_type == R_SCORE_ABS32 || r_type == R_SCORE_REL32)
  else if (r_type == R_SCORE_ABS32 || r_type == R_SCORE_REL32)
    {
    {
      addend = (bfd_get_32 (input_bfd, hit_data) >> howto->bitpos) & howto->src_mask;
      addend = (bfd_get_32 (input_bfd, hit_data) >> howto->bitpos) & howto->src_mask;
    }
    }
  else
  else
    {
    {
      addend = (score_bfd_get_32 (input_bfd, hit_data) >> howto->bitpos) & howto->src_mask;
      addend = (score_bfd_get_32 (input_bfd, hit_data) >> howto->bitpos) & howto->src_mask;
    }
    }
 
 
  /* If we haven't already determined the GOT offset, or the GP value,
  /* If we haven't already determined the GOT offset, or the GP value,
     and we're going to need it, get it now.  */
     and we're going to need it, get it now.  */
  switch (r_type)
  switch (r_type)
    {
    {
    case R_SCORE_CALL15:
    case R_SCORE_CALL15:
    case R_SCORE_GOT15:
    case R_SCORE_GOT15:
      if (!local_p)
      if (!local_p)
        {
        {
          g = score_elf_global_got_index (elf_hash_table (info)->dynobj,
          g = score_elf_global_got_index (elf_hash_table (info)->dynobj,
                                          (struct elf_link_hash_entry *) h);
                                          (struct elf_link_hash_entry *) h);
          if ((! elf_hash_table (info)->dynamic_sections_created
          if ((! elf_hash_table (info)->dynamic_sections_created
               || (info->shared
               || (info->shared
                   && (info->symbolic || h->root.dynindx == -1)
                   && (info->symbolic || h->root.dynindx == -1)
                   && h->root.def_regular)))
                   && h->root.def_regular)))
            {
            {
              /* This is a static link or a -Bsymbolic link.  The
              /* This is a static link or a -Bsymbolic link.  The
                 symbol is defined locally, or was forced to be local.
                 symbol is defined locally, or was forced to be local.
                 We must initialize this entry in the GOT.  */
                 We must initialize this entry in the GOT.  */
              bfd *tmpbfd = elf_hash_table (info)->dynobj;
              bfd *tmpbfd = elf_hash_table (info)->dynobj;
              asection *sgot = score_elf_got_section (tmpbfd, FALSE);
              asection *sgot = score_elf_got_section (tmpbfd, FALSE);
              score_bfd_put_32 (tmpbfd, value, sgot->contents + g);
              score_bfd_put_32 (tmpbfd, value, sgot->contents + g);
            }
            }
        }
        }
      else if (r_type == R_SCORE_GOT15 || r_type == R_SCORE_CALL15)
      else if (r_type == R_SCORE_GOT15 || r_type == R_SCORE_CALL15)
        {
        {
          /* There's no need to create a local GOT entry here; the
          /* There's no need to create a local GOT entry here; the
             calculation for a local GOT15 entry does not involve G.  */
             calculation for a local GOT15 entry does not involve G.  */
          ;
          ;
        }
        }
      else
      else
        {
        {
          g = score_elf_local_got_index (output_bfd, input_bfd, info,
          g = score_elf_local_got_index (output_bfd, input_bfd, info,
                                         symbol + addend, r_symndx, h, r_type);
                                         symbol + addend, r_symndx, h, r_type);
            if (g == MINUS_ONE)
            if (g == MINUS_ONE)
            return bfd_reloc_outofrange;
            return bfd_reloc_outofrange;
        }
        }
 
 
      /* Convert GOT indices to actual offsets.  */
      /* Convert GOT indices to actual offsets.  */
      g = score_elf_got_offset_from_index (elf_hash_table (info)->dynobj,
      g = score_elf_got_offset_from_index (elf_hash_table (info)->dynobj,
                                           output_bfd, input_bfd, g);
                                           output_bfd, input_bfd, g);
      break;
      break;
 
 
    case R_SCORE_HI16:
    case R_SCORE_HI16:
    case R_SCORE_LO16:
    case R_SCORE_LO16:
    case R_SCORE_GPREL32:
    case R_SCORE_GPREL32:
      gp0 = _bfd_get_gp_value (input_bfd);
      gp0 = _bfd_get_gp_value (input_bfd);
      gp = _bfd_get_gp_value (output_bfd);
      gp = _bfd_get_gp_value (output_bfd);
      break;
      break;
 
 
    case R_SCORE_GP15:
    case R_SCORE_GP15:
      gp = _bfd_get_gp_value (output_bfd);
      gp = _bfd_get_gp_value (output_bfd);
 
 
    default:
    default:
      break;
      break;
    }
    }
 
 
  switch (r_type)
  switch (r_type)
    {
    {
    case R_SCORE_NONE:
    case R_SCORE_NONE:
      return bfd_reloc_ok;
      return bfd_reloc_ok;
 
 
    case R_SCORE_ABS32:
    case R_SCORE_ABS32:
    case R_SCORE_REL32:
    case R_SCORE_REL32:
      if ((info->shared
      if ((info->shared
           || (elf_hash_table (info)->dynamic_sections_created
           || (elf_hash_table (info)->dynamic_sections_created
               && h != NULL
               && h != NULL
               && h->root.def_dynamic
               && h->root.def_dynamic
               && !h->root.def_regular))
               && !h->root.def_regular))
           && r_symndx != 0
           && r_symndx != 0
           && (input_section->flags & SEC_ALLOC) != 0)
           && (input_section->flags & SEC_ALLOC) != 0)
        {
        {
          /* If we're creating a shared library, or this relocation is against a symbol
          /* If we're creating a shared library, or this relocation is against a symbol
             in a shared library, then we can't know where the symbol will end up.
             in a shared library, then we can't know where the symbol will end up.
             So, we create a relocation record in the output, and leave the job up
             So, we create a relocation record in the output, and leave the job up
             to the dynamic linker.  */
             to the dynamic linker.  */
          value = addend;
          value = addend;
          if (!score_elf_create_dynamic_relocation (output_bfd, info, rel, h,
          if (!score_elf_create_dynamic_relocation (output_bfd, info, rel, h,
                                                    symbol, &value,
                                                    symbol, &value,
                                                    input_section))
                                                    input_section))
            return bfd_reloc_undefined;
            return bfd_reloc_undefined;
        }
        }
      else if (r_symndx == 0)
      else if (r_symndx == 0)
        /* r_symndx will be zero only for relocs against symbols
        /* r_symndx will be zero only for relocs against symbols
           from removed linkonce sections, or sections discarded by
           from removed linkonce sections, or sections discarded by
           a linker script.  */
           a linker script.  */
        value = 0;
        value = 0;
      else
      else
        {
        {
          if (r_type != R_SCORE_REL32)
          if (r_type != R_SCORE_REL32)
            value = symbol + addend;
            value = symbol + addend;
          else
          else
            value = addend;
            value = addend;
        }
        }
      value &= howto->dst_mask;
      value &= howto->dst_mask;
      bfd_put_32 (input_bfd, value, hit_data);
      bfd_put_32 (input_bfd, value, hit_data);
      return bfd_reloc_ok;
      return bfd_reloc_ok;
 
 
    case R_SCORE_ABS16:
    case R_SCORE_ABS16:
      value += addend;
      value += addend;
      if ((long)value > 0x7fff || (long)value < -0x8000)
      if ((long)value > 0x7fff || (long)value < -0x8000)
        return bfd_reloc_overflow;
        return bfd_reloc_overflow;
      score_bfd_put_16 (input_bfd, value, hit_data);
      score_bfd_put_16 (input_bfd, value, hit_data);
      return bfd_reloc_ok;
      return bfd_reloc_ok;
 
 
    case R_SCORE_24:
    case R_SCORE_24:
      addend = score_bfd_get_32 (input_bfd, hit_data);
      addend = score_bfd_get_32 (input_bfd, hit_data);
      offset = (((addend & howto->src_mask) >> 1) & 0x1ff8000) | ((addend & howto->src_mask) & 0x7fff);
      offset = (((addend & howto->src_mask) >> 1) & 0x1ff8000) | ((addend & howto->src_mask) & 0x7fff);
      if ((offset & 0x1000000) != 0)
      if ((offset & 0x1000000) != 0)
        offset |= 0xfe000000;
        offset |= 0xfe000000;
      value += offset;
      value += offset;
      abs_value = abs (value - rel_addr);
      abs_value = abs (value - rel_addr);
      if ((abs_value & 0xfe000000) != 0)
      if ((abs_value & 0xfe000000) != 0)
        return bfd_reloc_overflow;
        return bfd_reloc_overflow;
      addend = (addend & ~howto->src_mask)
      addend = (addend & ~howto->src_mask)
                | (((value << 1) & howto->src_mask) & 0x3ff0000) | (value & 0x7fff);
                | (((value << 1) & howto->src_mask) & 0x3ff0000) | (value & 0x7fff);
      score_bfd_put_32 (input_bfd, addend, hit_data);
      score_bfd_put_32 (input_bfd, addend, hit_data);
      return bfd_reloc_ok;
      return bfd_reloc_ok;
 
 
    /* signed imm32.  */
    /* signed imm32.  */
    case R_SCORE_IMM30:
    case R_SCORE_IMM30:
      {
      {
        int not_word_align_p = 0;
        int not_word_align_p = 0;
        bfd_vma imm_offset = 0;
        bfd_vma imm_offset = 0;
        addend = score_bfd_get_48 (input_bfd, hit_data);
        addend = score_bfd_get_48 (input_bfd, hit_data);
        imm_offset = ((addend >> 7) & 0xff)
        imm_offset = ((addend >> 7) & 0xff)
                     | (((addend >> 16) & 0x7fff) << 8)
                     | (((addend >> 16) & 0x7fff) << 8)
                     | (((addend >> 32) & 0x7f) << 23);
                     | (((addend >> 32) & 0x7f) << 23);
        imm_offset <<= howto->rightshift;
        imm_offset <<= howto->rightshift;
        value += imm_offset;
        value += imm_offset;
        value &= 0xffffffff;
        value &= 0xffffffff;
 
 
        /* Check lw48/sw48 rd, value/label word align.  */
        /* Check lw48/sw48 rd, value/label word align.  */
        if ((value & 0x3) != 0)
        if ((value & 0x3) != 0)
          not_word_align_p = 1;
          not_word_align_p = 1;
 
 
        value >>= howto->rightshift;
        value >>= howto->rightshift;
        addend = (addend & ~howto->src_mask)
        addend = (addend & ~howto->src_mask)
                 | (((value & 0xff) >> 0) << 7)
                 | (((value & 0xff) >> 0) << 7)
                 | (((value & 0x7fff00) >> 8) << 16)
                 | (((value & 0x7fff00) >> 8) << 16)
                 | (((value & 0x3f800000) >> 23) << 32);
                 | (((value & 0x3f800000) >> 23) << 32);
        score_bfd_put_48 (input_bfd, addend, hit_data);
        score_bfd_put_48 (input_bfd, addend, hit_data);
        if (not_word_align_p)
        if (not_word_align_p)
          return bfd_reloc_other;
          return bfd_reloc_other;
        else
        else
          return bfd_reloc_ok;
          return bfd_reloc_ok;
      }
      }
 
 
    case R_SCORE_IMM32:
    case R_SCORE_IMM32:
      {
      {
        bfd_vma imm_offset = 0;
        bfd_vma imm_offset = 0;
        addend = score_bfd_get_48 (input_bfd, hit_data);
        addend = score_bfd_get_48 (input_bfd, hit_data);
        imm_offset = ((addend >> 5) & 0x3ff)
        imm_offset = ((addend >> 5) & 0x3ff)
                     | (((addend >> 16) & 0x7fff) << 10)
                     | (((addend >> 16) & 0x7fff) << 10)
                     | (((addend >> 32) & 0x7f) << 25);
                     | (((addend >> 32) & 0x7f) << 25);
        value += imm_offset;
        value += imm_offset;
        value &= 0xffffffff;
        value &= 0xffffffff;
        addend = (addend & ~howto->src_mask)
        addend = (addend & ~howto->src_mask)
                 | ((value & 0x3ff) << 5)
                 | ((value & 0x3ff) << 5)
                 | (((value >> 10) & 0x7fff) << 16)
                 | (((value >> 10) & 0x7fff) << 16)
                 | (((value >> 25) & 0x7f) << 32);
                 | (((value >> 25) & 0x7f) << 32);
        score_bfd_put_48 (input_bfd, addend, hit_data);
        score_bfd_put_48 (input_bfd, addend, hit_data);
        return bfd_reloc_ok;
        return bfd_reloc_ok;
      }
      }
 
 
    case R_SCORE_PC19:
    case R_SCORE_PC19:
      addend = score_bfd_get_32 (input_bfd, hit_data);
      addend = score_bfd_get_32 (input_bfd, hit_data);
      offset = (((addend & howto->src_mask) & 0x3ff0000) >> 6) | ((addend & howto->src_mask) & 0x3ff);
      offset = (((addend & howto->src_mask) & 0x3ff0000) >> 6) | ((addend & howto->src_mask) & 0x3ff);
      if ((offset & 0x80000) != 0)
      if ((offset & 0x80000) != 0)
        offset |= 0xfff00000;
        offset |= 0xfff00000;
      abs_value = value = value - rel_addr + offset;
      abs_value = value = value - rel_addr + offset;
      /* exceed 20 bit : overflow.  */
      /* exceed 20 bit : overflow.  */
      if ((abs_value & 0x80000000) == 0x80000000)
      if ((abs_value & 0x80000000) == 0x80000000)
        abs_value = 0xffffffff - value + 1;
        abs_value = 0xffffffff - value + 1;
      if ((abs_value & 0xfff80000) != 0)
      if ((abs_value & 0xfff80000) != 0)
        return bfd_reloc_overflow;
        return bfd_reloc_overflow;
      addend = (addend & ~howto->src_mask)
      addend = (addend & ~howto->src_mask)
                | (((value << 6) & howto->src_mask) & 0x3ff0000) | (value & 0x3ff);
                | (((value << 6) & howto->src_mask) & 0x3ff0000) | (value & 0x3ff);
      score_bfd_put_32 (input_bfd, addend, hit_data);
      score_bfd_put_32 (input_bfd, addend, hit_data);
      return bfd_reloc_ok;
      return bfd_reloc_ok;
 
 
    case R_SCORE16_11:
    case R_SCORE16_11:
      addend = score_bfd_get_16 (input_bfd, hit_data);
      addend = score_bfd_get_16 (input_bfd, hit_data);
      offset = addend & howto->src_mask;
      offset = addend & howto->src_mask;
      if ((offset & 0x800) != 0)        /* Offset is negative.  */
      if ((offset & 0x800) != 0)        /* Offset is negative.  */
        offset |= 0xfffff000;
        offset |= 0xfffff000;
      value += offset;
      value += offset;
      abs_value = abs (value - rel_addr);
      abs_value = abs (value - rel_addr);
      if ((abs_value & 0xfffff000) != 0)
      if ((abs_value & 0xfffff000) != 0)
        return bfd_reloc_overflow;
        return bfd_reloc_overflow;
      addend = (addend & ~howto->src_mask) | (value & howto->src_mask);
      addend = (addend & ~howto->src_mask) | (value & howto->src_mask);
      score_bfd_put_16 (input_bfd, addend, hit_data);
      score_bfd_put_16 (input_bfd, addend, hit_data);
      return bfd_reloc_ok;
      return bfd_reloc_ok;
 
 
    case R_SCORE16_PC8:
    case R_SCORE16_PC8:
      addend = score_bfd_get_16 (input_bfd, hit_data);
      addend = score_bfd_get_16 (input_bfd, hit_data);
      offset = (addend & howto->src_mask) << 1;
      offset = (addend & howto->src_mask) << 1;
      if ((offset & 0x200) != 0)        /* Offset is negative.  */
      if ((offset & 0x200) != 0)        /* Offset is negative.  */
        offset |= 0xfffffe00;
        offset |= 0xfffffe00;
      abs_value = value = value - rel_addr + offset;
      abs_value = value = value - rel_addr + offset;
      /* Sign bit + exceed 9 bit.  */
      /* Sign bit + exceed 9 bit.  */
      if (((value & 0xfffffe00) != 0) && ((value & 0xfffffe00) != 0xfffffe00))
      if (((value & 0xfffffe00) != 0) && ((value & 0xfffffe00) != 0xfffffe00))
        return bfd_reloc_overflow;
        return bfd_reloc_overflow;
      value >>= 1;
      value >>= 1;
      addend = (addend & ~howto->src_mask) | (value & howto->src_mask);
      addend = (addend & ~howto->src_mask) | (value & howto->src_mask);
      score_bfd_put_16 (input_bfd, addend, hit_data);
      score_bfd_put_16 (input_bfd, addend, hit_data);
      return bfd_reloc_ok;
      return bfd_reloc_ok;
 
 
    case R_SCORE_BCMP:
    case R_SCORE_BCMP:
      addend = score_bfd_get_32 (input_bfd, hit_data);
      addend = score_bfd_get_32 (input_bfd, hit_data);
      offset = (addend & howto->src_mask) << howto->rightshift;
      offset = (addend & howto->src_mask) << howto->rightshift;
      if ((offset & 0x200) != 0)        /* Offset is negative.  */
      if ((offset & 0x200) != 0)        /* Offset is negative.  */
        offset |= 0xfffffe00;
        offset |= 0xfffffe00;
      value = value - rel_addr + offset;
      value = value - rel_addr + offset;
      /* Sign bit + exceed 9 bit.  */
      /* Sign bit + exceed 9 bit.  */
      if (((value & 0xfffffe00) != 0) && ((value & 0xfffffe00) != 0xfffffe00))
      if (((value & 0xfffffe00) != 0) && ((value & 0xfffffe00) != 0xfffffe00))
        return bfd_reloc_overflow;
        return bfd_reloc_overflow;
      value >>= howto->rightshift;
      value >>= howto->rightshift;
      addend = (addend & ~howto->src_mask)
      addend = (addend & ~howto->src_mask)
               | (value & 0x1)
               | (value & 0x1)
               | (((value >> 1) & 0x7) << 7)
               | (((value >> 1) & 0x7) << 7)
               | (((value >> 4) & 0x1f) << 21);
               | (((value >> 4) & 0x1f) << 21);
      score_bfd_put_32 (input_bfd, addend, hit_data);
      score_bfd_put_32 (input_bfd, addend, hit_data);
      return bfd_reloc_ok;
      return bfd_reloc_ok;
 
 
    case R_SCORE_HI16:
    case R_SCORE_HI16:
      return bfd_reloc_ok;
      return bfd_reloc_ok;
 
 
    case R_SCORE_LO16:
    case R_SCORE_LO16:
      hi16_addend = score_bfd_get_32 (input_bfd, hit_data - 4);
      hi16_addend = score_bfd_get_32 (input_bfd, hit_data - 4);
      hi16_offset = ((((hi16_addend >> 16) & 0x3) << 15) | (hi16_addend & 0x7fff)) >> 1;
      hi16_offset = ((((hi16_addend >> 16) & 0x3) << 15) | (hi16_addend & 0x7fff)) >> 1;
      addend = score_bfd_get_32 (input_bfd, hit_data);
      addend = score_bfd_get_32 (input_bfd, hit_data);
      offset = ((((addend >> 16) & 0x3) << 15) | (addend & 0x7fff)) >> 1;
      offset = ((((addend >> 16) & 0x3) << 15) | (addend & 0x7fff)) >> 1;
      offset = (hi16_offset << 16) | (offset & 0xffff);
      offset = (hi16_offset << 16) | (offset & 0xffff);
 
 
      if (!gp_disp_p)
      if (!gp_disp_p)
        uvalue = value + offset;
        uvalue = value + offset;
      else
      else
        uvalue = offset + gp - rel_addr + 4;
        uvalue = offset + gp - rel_addr + 4;
 
 
      hi16_offset = (uvalue >> 16) << 1;
      hi16_offset = (uvalue >> 16) << 1;
      hi16_value = (hi16_addend & (~(howto->dst_mask)))
      hi16_value = (hi16_addend & (~(howto->dst_mask)))
                        | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000);
                        | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000);
      score_bfd_put_32 (input_bfd, hi16_value, hit_data - 4);
      score_bfd_put_32 (input_bfd, hi16_value, hit_data - 4);
      offset = (uvalue & 0xffff) << 1;
      offset = (uvalue & 0xffff) << 1;
      value = (addend & (~(howto->dst_mask))) | (offset & 0x7fff) | ((offset << 1) & 0x30000);
      value = (addend & (~(howto->dst_mask))) | (offset & 0x7fff) | ((offset << 1) & 0x30000);
      score_bfd_put_32 (input_bfd, value, hit_data);
      score_bfd_put_32 (input_bfd, value, hit_data);
      return bfd_reloc_ok;
      return bfd_reloc_ok;
 
 
    case R_SCORE_GP15:
    case R_SCORE_GP15:
      addend = score_bfd_get_32 (input_bfd, hit_data);
      addend = score_bfd_get_32 (input_bfd, hit_data);
      offset = addend & 0x7fff;
      offset = addend & 0x7fff;
      if ((offset & 0x4000) == 0x4000)
      if ((offset & 0x4000) == 0x4000)
        offset |= 0xffffc000;
        offset |= 0xffffc000;
      value = value + offset - gp;
      value = value + offset - gp;
      if (((value & 0xffffc000) != 0) && ((value & 0xffffc000) != 0xffffc000))
      if (((value & 0xffffc000) != 0) && ((value & 0xffffc000) != 0xffffc000))
        return bfd_reloc_overflow;
        return bfd_reloc_overflow;
      value = (addend & ~howto->src_mask) | (value & howto->src_mask);
      value = (addend & ~howto->src_mask) | (value & howto->src_mask);
      score_bfd_put_32 (input_bfd, value, hit_data);
      score_bfd_put_32 (input_bfd, value, hit_data);
      return bfd_reloc_ok;
      return bfd_reloc_ok;
 
 
    case R_SCORE_GOT15:
    case R_SCORE_GOT15:
    case R_SCORE_CALL15:
    case R_SCORE_CALL15:
      if (local_p)
      if (local_p)
        {
        {
          bfd_boolean forced;
          bfd_boolean forced;
 
 
          /* The special case is when the symbol is forced to be local.  We need the
          /* The special case is when the symbol is forced to be local.  We need the
             full address in the GOT since no R_SCORE_GOT_LO16 relocation follows.  */
             full address in the GOT since no R_SCORE_GOT_LO16 relocation follows.  */
          forced = ! score_elf_local_relocation_p (input_bfd, rel,
          forced = ! score_elf_local_relocation_p (input_bfd, rel,
                                                   local_sections, FALSE);
                                                   local_sections, FALSE);
          value = score_elf_got16_entry (output_bfd, input_bfd, info,
          value = score_elf_got16_entry (output_bfd, input_bfd, info,
                                         symbol + addend, forced);
                                         symbol + addend, forced);
          if (value == MINUS_ONE)
          if (value == MINUS_ONE)
            return bfd_reloc_outofrange;
            return bfd_reloc_outofrange;
          value = score_elf_got_offset_from_index (elf_hash_table (info)->dynobj,
          value = score_elf_got_offset_from_index (elf_hash_table (info)->dynobj,
                                                   output_bfd, input_bfd, value);
                                                   output_bfd, input_bfd, value);
        }
        }
      else
      else
        {
        {
          value = g;
          value = g;
        }
        }
 
 
      if ((long) value > 0x3fff || (long) value < -0x4000)
      if ((long) value > 0x3fff || (long) value < -0x4000)
        return bfd_reloc_overflow;
        return bfd_reloc_overflow;
 
 
      addend = score_bfd_get_32 (input_bfd, hit_data);
      addend = score_bfd_get_32 (input_bfd, hit_data);
      value = (addend & ~howto->dst_mask) | (value & howto->dst_mask);
      value = (addend & ~howto->dst_mask) | (value & howto->dst_mask);
      score_bfd_put_32 (input_bfd, value, hit_data);
      score_bfd_put_32 (input_bfd, value, hit_data);
      return bfd_reloc_ok;
      return bfd_reloc_ok;
 
 
    case R_SCORE_GPREL32:
    case R_SCORE_GPREL32:
      value = (addend + symbol - gp);
      value = (addend + symbol - gp);
      value &= howto->dst_mask;
      value &= howto->dst_mask;
      score_bfd_put_32 (input_bfd, value, hit_data);
      score_bfd_put_32 (input_bfd, value, hit_data);
      return bfd_reloc_ok;
      return bfd_reloc_ok;
 
 
    case R_SCORE_GOT_LO16:
    case R_SCORE_GOT_LO16:
      addend = score_bfd_get_32 (input_bfd, hit_data);
      addend = score_bfd_get_32 (input_bfd, hit_data);
      value = (((addend >> 16) & 0x3) << 14) | ((addend & 0x7fff) >> 1);
      value = (((addend >> 16) & 0x3) << 14) | ((addend & 0x7fff) >> 1);
      value += symbol;
      value += symbol;
      value = (addend & (~(howto->dst_mask))) | ((value & 0x3fff) << 1)
      value = (addend & (~(howto->dst_mask))) | ((value & 0x3fff) << 1)
               | (((value >> 14) & 0x3) << 16);
               | (((value >> 14) & 0x3) << 16);
 
 
      score_bfd_put_32 (input_bfd, value, hit_data);
      score_bfd_put_32 (input_bfd, value, hit_data);
      return bfd_reloc_ok;
      return bfd_reloc_ok;
 
 
    case R_SCORE_DUMMY_HI16:
    case R_SCORE_DUMMY_HI16:
      return bfd_reloc_ok;
      return bfd_reloc_ok;
 
 
    case R_SCORE_GNU_VTINHERIT:
    case R_SCORE_GNU_VTINHERIT:
    case R_SCORE_GNU_VTENTRY:
    case R_SCORE_GNU_VTENTRY:
      /* We don't do anything with these at present.  */
      /* We don't do anything with these at present.  */
      return bfd_reloc_continue;
      return bfd_reloc_continue;
 
 
    default:
    default:
      return bfd_reloc_notsupported;
      return bfd_reloc_notsupported;
    }
    }
}
}
 
 
/* Score backend functions.  */
/* Score backend functions.  */
static void
static void
s3_bfd_score_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED,
s3_bfd_score_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED,
                            arelent *bfd_reloc,
                            arelent *bfd_reloc,
                            Elf_Internal_Rela *elf_reloc)
                            Elf_Internal_Rela *elf_reloc)
{
{
  unsigned int r_type;
  unsigned int r_type;
 
 
  r_type = ELF32_R_TYPE (elf_reloc->r_info);
  r_type = ELF32_R_TYPE (elf_reloc->r_info);
  if (r_type >= ARRAY_SIZE (elf32_score_howto_table))
  if (r_type >= ARRAY_SIZE (elf32_score_howto_table))
    bfd_reloc->howto = NULL;
    bfd_reloc->howto = NULL;
  else
  else
    bfd_reloc->howto = &elf32_score_howto_table[r_type];
    bfd_reloc->howto = &elf32_score_howto_table[r_type];
}
}
 
 
/* Relocate an score ELF section.  */
/* Relocate an score ELF section.  */
static bfd_boolean
static bfd_boolean
s3_bfd_score_elf_relocate_section (bfd *output_bfd,
s3_bfd_score_elf_relocate_section (bfd *output_bfd,
                                   struct bfd_link_info *info,
                                   struct bfd_link_info *info,
                                   bfd *input_bfd,
                                   bfd *input_bfd,
                                   asection *input_section,
                                   asection *input_section,
                                   bfd_byte *contents,
                                   bfd_byte *contents,
                                   Elf_Internal_Rela *relocs,
                                   Elf_Internal_Rela *relocs,
                                   Elf_Internal_Sym *local_syms,
                                   Elf_Internal_Sym *local_syms,
                                   asection **local_sections)
                                   asection **local_sections)
{
{
  Elf_Internal_Shdr *symtab_hdr;
  Elf_Internal_Shdr *symtab_hdr;
  struct elf_link_hash_entry **sym_hashes;
  struct elf_link_hash_entry **sym_hashes;
  Elf_Internal_Rela *rel;
  Elf_Internal_Rela *rel;
  Elf_Internal_Rela *relend;
  Elf_Internal_Rela *relend;
  const char *name;
  const char *name;
  unsigned long offset;
  unsigned long offset;
  unsigned long hi16_addend, hi16_offset, hi16_value, uvalue;
  unsigned long hi16_addend, hi16_offset, hi16_value, uvalue;
  size_t extsymoff;
  size_t extsymoff;
  bfd_boolean gp_disp_p = FALSE;
  bfd_boolean gp_disp_p = FALSE;
 
 
  /* Sort dynsym.  */
  /* Sort dynsym.  */
  if (elf_hash_table (info)->dynamic_sections_created)
  if (elf_hash_table (info)->dynamic_sections_created)
    {
    {
      bfd_size_type dynsecsymcount = 0;
      bfd_size_type dynsecsymcount = 0;
      if (info->shared)
      if (info->shared)
        {
        {
          asection * p;
          asection * p;
          const struct elf_backend_data *bed = get_elf_backend_data (output_bfd);
          const struct elf_backend_data *bed = get_elf_backend_data (output_bfd);
 
 
          for (p = output_bfd->sections; p ; p = p->next)
          for (p = output_bfd->sections; p ; p = p->next)
            if ((p->flags & SEC_EXCLUDE) == 0
            if ((p->flags & SEC_EXCLUDE) == 0
                && (p->flags & SEC_ALLOC) != 0
                && (p->flags & SEC_ALLOC) != 0
                && !(*bed->elf_backend_omit_section_dynsym) (output_bfd, info, p))
                && !(*bed->elf_backend_omit_section_dynsym) (output_bfd, info, p))
              ++ dynsecsymcount;
              ++ dynsecsymcount;
        }
        }
 
 
      if (!score_elf_sort_hash_table (info, dynsecsymcount + 1))
      if (!score_elf_sort_hash_table (info, dynsecsymcount + 1))
        return FALSE;
        return FALSE;
    }
    }
 
 
  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
  extsymoff = (elf_bad_symtab (input_bfd)) ? 0 : symtab_hdr->sh_info;
  extsymoff = (elf_bad_symtab (input_bfd)) ? 0 : symtab_hdr->sh_info;
  sym_hashes = elf_sym_hashes (input_bfd);
  sym_hashes = elf_sym_hashes (input_bfd);
  rel = relocs;
  rel = relocs;
  relend = relocs + input_section->reloc_count;
  relend = relocs + input_section->reloc_count;
  for (; rel < relend; rel++)
  for (; rel < relend; rel++)
    {
    {
      int r_type;
      int r_type;
      reloc_howto_type *howto;
      reloc_howto_type *howto;
      unsigned long r_symndx;
      unsigned long r_symndx;
      Elf_Internal_Sym *sym;
      Elf_Internal_Sym *sym;
      asection *sec;
      asection *sec;
      struct score_elf_link_hash_entry *h;
      struct score_elf_link_hash_entry *h;
      bfd_vma relocation = 0;
      bfd_vma relocation = 0;
      bfd_reloc_status_type r;
      bfd_reloc_status_type r;
      arelent bfd_reloc;
      arelent bfd_reloc;
 
 
      r_symndx = ELF32_R_SYM (rel->r_info);
      r_symndx = ELF32_R_SYM (rel->r_info);
      r_type = ELF32_R_TYPE (rel->r_info);
      r_type = ELF32_R_TYPE (rel->r_info);
 
 
      s3_bfd_score_info_to_howto (input_bfd, &bfd_reloc, (Elf_Internal_Rela *) rel);
      s3_bfd_score_info_to_howto (input_bfd, &bfd_reloc, (Elf_Internal_Rela *) rel);
      howto = bfd_reloc.howto;
      howto = bfd_reloc.howto;
 
 
      h = NULL;
      h = NULL;
      sym = NULL;
      sym = NULL;
      sec = NULL;
      sec = NULL;
 
 
      if (r_symndx < extsymoff)
      if (r_symndx < extsymoff)
        {
        {
          sym = local_syms + r_symndx;
          sym = local_syms + r_symndx;
          sec = local_sections[r_symndx];
          sec = local_sections[r_symndx];
          relocation = (sec->output_section->vma
          relocation = (sec->output_section->vma
                        + sec->output_offset
                        + sec->output_offset
                        + sym->st_value);
                        + sym->st_value);
          name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, sec);
          name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, sec);
 
 
          if (!info->relocatable
          if (!info->relocatable
              && (sec->flags & SEC_MERGE)
              && (sec->flags & SEC_MERGE)
              && ELF_ST_TYPE (sym->st_info) == STT_SECTION)
              && ELF_ST_TYPE (sym->st_info) == STT_SECTION)
            {
            {
              asection *msec;
              asection *msec;
              bfd_vma addend, value;
              bfd_vma addend, value;
 
 
              switch (r_type)
              switch (r_type)
                {
                {
                case R_SCORE_HI16:
                case R_SCORE_HI16:
                  break;
                  break;
                case R_SCORE_LO16:
                case R_SCORE_LO16:
                  hi16_addend = score_bfd_get_32 (input_bfd, contents + rel->r_offset - 4);
                  hi16_addend = score_bfd_get_32 (input_bfd, contents + rel->r_offset - 4);
                  hi16_offset = ((((hi16_addend >> 16) & 0x3) << 15) | (hi16_addend & 0x7fff)) >> 1;
                  hi16_offset = ((((hi16_addend >> 16) & 0x3) << 15) | (hi16_addend & 0x7fff)) >> 1;
                  value = score_bfd_get_32 (input_bfd, contents + rel->r_offset);
                  value = score_bfd_get_32 (input_bfd, contents + rel->r_offset);
                  offset = ((((value >> 16) & 0x3) << 15) | (value & 0x7fff)) >> 1;
                  offset = ((((value >> 16) & 0x3) << 15) | (value & 0x7fff)) >> 1;
                  addend = (hi16_offset << 16) | (offset & 0xffff);
                  addend = (hi16_offset << 16) | (offset & 0xffff);
                  msec = sec;
                  msec = sec;
                  addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend);
                  addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend);
                  addend -= relocation;
                  addend -= relocation;
                  addend += msec->output_section->vma + msec->output_offset;
                  addend += msec->output_section->vma + msec->output_offset;
                  uvalue = addend;
                  uvalue = addend;
                  hi16_offset = (uvalue >> 16) << 1;
                  hi16_offset = (uvalue >> 16) << 1;
                  hi16_value = (hi16_addend & (~(howto->dst_mask)))
                  hi16_value = (hi16_addend & (~(howto->dst_mask)))
                    | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000);
                    | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000);
                  score_bfd_put_32 (input_bfd, hi16_value, contents + rel->r_offset - 4);
                  score_bfd_put_32 (input_bfd, hi16_value, contents + rel->r_offset - 4);
                  offset = (uvalue & 0xffff) << 1;
                  offset = (uvalue & 0xffff) << 1;
                  value = (value & (~(howto->dst_mask)))
                  value = (value & (~(howto->dst_mask)))
                    | (offset & 0x7fff) | ((offset << 1) & 0x30000);
                    | (offset & 0x7fff) | ((offset << 1) & 0x30000);
                  score_bfd_put_32 (input_bfd, value, contents + rel->r_offset);
                  score_bfd_put_32 (input_bfd, value, contents + rel->r_offset);
                  break;
                  break;
 
 
                case R_SCORE_IMM32:
                case R_SCORE_IMM32:
                  {
                  {
                    value = score_bfd_get_48 (input_bfd, contents + rel->r_offset);
                    value = score_bfd_get_48 (input_bfd, contents + rel->r_offset);
                    addend = ((value >> 5) & 0x3ff)
                    addend = ((value >> 5) & 0x3ff)
                              | (((value >> 16) & 0x7fff) << 10)
                              | (((value >> 16) & 0x7fff) << 10)
                              | (((value >> 32) & 0x7f) << 25);
                              | (((value >> 32) & 0x7f) << 25);
                    msec = sec;
                    msec = sec;
                    addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend);
                    addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend);
                    addend -= relocation;
                    addend -= relocation;
                    addend += msec->output_section->vma + msec->output_offset;
                    addend += msec->output_section->vma + msec->output_offset;
                    addend &= 0xffffffff;
                    addend &= 0xffffffff;
                    value = (value & ~howto->src_mask)
                    value = (value & ~howto->src_mask)
                             | ((addend & 0x3ff) << 5)
                             | ((addend & 0x3ff) << 5)
                             | (((addend >> 10) & 0x7fff) << 16)
                             | (((addend >> 10) & 0x7fff) << 16)
                             | (((addend >> 25) & 0x7f) << 32);
                             | (((addend >> 25) & 0x7f) << 32);
                    score_bfd_put_48 (input_bfd, value, contents + rel->r_offset);
                    score_bfd_put_48 (input_bfd, value, contents + rel->r_offset);
                    break;
                    break;
                  }
                  }
 
 
                case R_SCORE_IMM30:
                case R_SCORE_IMM30:
                  {
                  {
                    int not_word_align_p = 0;
                    int not_word_align_p = 0;
                    value = score_bfd_get_48 (input_bfd, contents + rel->r_offset);
                    value = score_bfd_get_48 (input_bfd, contents + rel->r_offset);
                    addend = ((value >> 7) & 0xff)
                    addend = ((value >> 7) & 0xff)
                              | (((value >> 16) & 0x7fff) << 8)
                              | (((value >> 16) & 0x7fff) << 8)
                              | (((value >> 32) & 0x7f) << 23);
                              | (((value >> 32) & 0x7f) << 23);
                    addend <<= howto->rightshift;
                    addend <<= howto->rightshift;
                    msec = sec;
                    msec = sec;
                    addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend);
                    addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend);
                    addend -= relocation;
                    addend -= relocation;
                    addend += msec->output_section->vma + msec->output_offset;
                    addend += msec->output_section->vma + msec->output_offset;
                    addend &= 0xffffffff;
                    addend &= 0xffffffff;
 
 
                    /* Check lw48/sw48 rd, value/label word align.  */
                    /* Check lw48/sw48 rd, value/label word align.  */
                    if ((addend & 0x3) != 0)
                    if ((addend & 0x3) != 0)
                      not_word_align_p = 1;
                      not_word_align_p = 1;
 
 
                    addend >>= howto->rightshift;
                    addend >>= howto->rightshift;
                    value = (value & ~howto->src_mask)
                    value = (value & ~howto->src_mask)
                             | (((addend & 0xff) >> 0) << 7)
                             | (((addend & 0xff) >> 0) << 7)
                             | (((addend & 0x7fff00) >> 8) << 16)
                             | (((addend & 0x7fff00) >> 8) << 16)
                             | (((addend & 0x3f800000) >> 23) << 32);
                             | (((addend & 0x3f800000) >> 23) << 32);
                    score_bfd_put_48 (input_bfd, value, contents + rel->r_offset);
                    score_bfd_put_48 (input_bfd, value, contents + rel->r_offset);
 
 
                    if (not_word_align_p)
                    if (not_word_align_p)
                      return bfd_reloc_other;
                      return bfd_reloc_other;
                    else
                    else
                      break;
                      break;
                  }
                  }
 
 
                case R_SCORE_GOT_LO16:
                case R_SCORE_GOT_LO16:
                  value = score_bfd_get_32 (input_bfd, contents + rel->r_offset);
                  value = score_bfd_get_32 (input_bfd, contents + rel->r_offset);
                  addend = (((value >> 16) & 0x3) << 14) | ((value & 0x7fff) >> 1);
                  addend = (((value >> 16) & 0x3) << 14) | ((value & 0x7fff) >> 1);
                  msec = sec;
                  msec = sec;
                  addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend) - relocation;
                  addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend) - relocation;
                  addend += msec->output_section->vma + msec->output_offset;
                  addend += msec->output_section->vma + msec->output_offset;
                  value = (value & (~(howto->dst_mask))) | ((addend & 0x3fff) << 1)
                  value = (value & (~(howto->dst_mask))) | ((addend & 0x3fff) << 1)
                           | (((addend >> 14) & 0x3) << 16);
                           | (((addend >> 14) & 0x3) << 16);
 
 
                  score_bfd_put_32 (input_bfd, value, contents + rel->r_offset);
                  score_bfd_put_32 (input_bfd, value, contents + rel->r_offset);
                  break;
                  break;
 
 
                case R_SCORE_ABS32:
                case R_SCORE_ABS32:
                case R_SCORE_REL32:
                case R_SCORE_REL32:
                  value = bfd_get_32 (input_bfd, contents + rel->r_offset);
                  value = bfd_get_32 (input_bfd, contents + rel->r_offset);
                  /* Get the (signed) value from the instruction.  */
                  /* Get the (signed) value from the instruction.  */
                  addend = value & howto->src_mask;
                  addend = value & howto->src_mask;
                  if (addend & ((howto->src_mask + 1) >> 1))
                  if (addend & ((howto->src_mask + 1) >> 1))
                    {
                    {
                      bfd_signed_vma mask;
                      bfd_signed_vma mask;
 
 
                      mask = -1;
                      mask = -1;
                      mask &= ~howto->src_mask;
                      mask &= ~howto->src_mask;
                      addend |= mask;
                      addend |= mask;
                    }
                    }
                  msec = sec;
                  msec = sec;
                  addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend) - relocation;
                  addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend) - relocation;
                  addend += msec->output_section->vma + msec->output_offset;
                  addend += msec->output_section->vma + msec->output_offset;
                  value = (value & ~howto->dst_mask) | (addend & howto->dst_mask);
                  value = (value & ~howto->dst_mask) | (addend & howto->dst_mask);
                  bfd_put_32 (input_bfd, value, contents + rel->r_offset);
                  bfd_put_32 (input_bfd, value, contents + rel->r_offset);
                  break;
                  break;
 
 
                default:
                default:
                  value = score_bfd_get_32 (input_bfd, contents + rel->r_offset);
                  value = score_bfd_get_32 (input_bfd, contents + rel->r_offset);
                  /* Get the (signed) value from the instruction.  */
                  /* Get the (signed) value from the instruction.  */
                  addend = value & howto->src_mask;
                  addend = value & howto->src_mask;
                  if (addend & ((howto->src_mask + 1) >> 1))
                  if (addend & ((howto->src_mask + 1) >> 1))
                    {
                    {
                      bfd_signed_vma mask;
                      bfd_signed_vma mask;
 
 
                      mask = -1;
                      mask = -1;
                      mask &= ~howto->src_mask;
                      mask &= ~howto->src_mask;
                      addend |= mask;
                      addend |= mask;
                    }
                    }
                  msec = sec;
                  msec = sec;
                  addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend) - relocation;
                  addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend) - relocation;
                  addend += msec->output_section->vma + msec->output_offset;
                  addend += msec->output_section->vma + msec->output_offset;
                  value = (value & ~howto->dst_mask) | (addend & howto->dst_mask);
                  value = (value & ~howto->dst_mask) | (addend & howto->dst_mask);
                  score_bfd_put_32 (input_bfd, value, contents + rel->r_offset);
                  score_bfd_put_32 (input_bfd, value, contents + rel->r_offset);
                  break;
                  break;
                }
                }
            }
            }
        }
        }
      else
      else
        {
        {
          /* For global symbols we look up the symbol in the hash-table.  */
          /* For global symbols we look up the symbol in the hash-table.  */
          h = ((struct score_elf_link_hash_entry *)
          h = ((struct score_elf_link_hash_entry *)
               elf_sym_hashes (input_bfd) [r_symndx - extsymoff]);
               elf_sym_hashes (input_bfd) [r_symndx - extsymoff]);
          /* Find the real hash-table entry for this symbol.  */
          /* Find the real hash-table entry for this symbol.  */
          while (h->root.root.type == bfd_link_hash_indirect
          while (h->root.root.type == bfd_link_hash_indirect
                 || h->root.root.type == bfd_link_hash_warning)
                 || h->root.root.type == bfd_link_hash_warning)
            h = (struct score_elf_link_hash_entry *) h->root.root.u.i.link;
            h = (struct score_elf_link_hash_entry *) h->root.root.u.i.link;
 
 
          /* Record the name of this symbol, for our caller.  */
          /* Record the name of this symbol, for our caller.  */
          name = h->root.root.root.string;
          name = h->root.root.root.string;
 
 
          /* See if this is the special GP_DISP_LABEL symbol.  Note that such a
          /* See if this is the special GP_DISP_LABEL symbol.  Note that such a
             symbol must always be a global symbol.  */
             symbol must always be a global symbol.  */
          if (strcmp (name, GP_DISP_LABEL) == 0)
          if (strcmp (name, GP_DISP_LABEL) == 0)
            {
            {
              /* Relocations against GP_DISP_LABEL are permitted only with
              /* Relocations against GP_DISP_LABEL are permitted only with
                 R_SCORE_HI16 and R_SCORE_LO16 relocations.  */
                 R_SCORE_HI16 and R_SCORE_LO16 relocations.  */
              if (r_type != R_SCORE_HI16 && r_type != R_SCORE_LO16)
              if (r_type != R_SCORE_HI16 && r_type != R_SCORE_LO16)
                return bfd_reloc_notsupported;
                return bfd_reloc_notsupported;
 
 
              gp_disp_p = TRUE;
              gp_disp_p = TRUE;
            }
            }
 
 
          /* If this symbol is defined, calculate its address.  Note that
          /* If this symbol is defined, calculate its address.  Note that
              GP_DISP_LABEL is a magic symbol, always implicitly defined by the
              GP_DISP_LABEL is a magic symbol, always implicitly defined by the
              linker, so it's inappropriate to check to see whether or not
              linker, so it's inappropriate to check to see whether or not
              its defined.  */
              its defined.  */
          else if ((h->root.root.type == bfd_link_hash_defined
          else if ((h->root.root.type == bfd_link_hash_defined
                    || h->root.root.type == bfd_link_hash_defweak)
                    || h->root.root.type == bfd_link_hash_defweak)
                   && h->root.root.u.def.section)
                   && h->root.root.u.def.section)
            {
            {
              sec = h->root.root.u.def.section;
              sec = h->root.root.u.def.section;
              if (sec->output_section)
              if (sec->output_section)
                relocation = (h->root.root.u.def.value
                relocation = (h->root.root.u.def.value
                              + sec->output_section->vma
                              + sec->output_section->vma
                              + sec->output_offset);
                              + sec->output_offset);
              else
              else
                {
                {
                  relocation = h->root.root.u.def.value;
                  relocation = h->root.root.u.def.value;
                }
                }
            }
            }
          else if (h->root.root.type == bfd_link_hash_undefweak)
          else if (h->root.root.type == bfd_link_hash_undefweak)
            /* We allow relocations against undefined weak symbols, giving
            /* We allow relocations against undefined weak symbols, giving
               it the value zero, so that you can undefined weak functions
               it the value zero, so that you can undefined weak functions
               and check to see if they exist by looking at their addresses.  */
               and check to see if they exist by looking at their addresses.  */
            relocation = 0;
            relocation = 0;
          else if (info->unresolved_syms_in_objects == RM_IGNORE
          else if (info->unresolved_syms_in_objects == RM_IGNORE
                   && ELF_ST_VISIBILITY (h->root.other) == STV_DEFAULT)
                   && ELF_ST_VISIBILITY (h->root.other) == STV_DEFAULT)
            relocation = 0;
            relocation = 0;
          else if (strcmp (name, "_DYNAMIC_LINK") == 0)
          else if (strcmp (name, "_DYNAMIC_LINK") == 0)
            {
            {
              /* If this is a dynamic link, we should have created a _DYNAMIC_LINK symbol
              /* If this is a dynamic link, we should have created a _DYNAMIC_LINK symbol
                 in s3_bfd_score_elf_create_dynamic_sections.  Otherwise, we should define
                 in s3_bfd_score_elf_create_dynamic_sections.  Otherwise, we should define
                 the symbol with a value of 0.  */
                 the symbol with a value of 0.  */
              BFD_ASSERT (! info->shared);
              BFD_ASSERT (! info->shared);
              BFD_ASSERT (bfd_get_section_by_name (output_bfd, ".dynamic") == NULL);
              BFD_ASSERT (bfd_get_section_by_name (output_bfd, ".dynamic") == NULL);
              relocation = 0;
              relocation = 0;
            }
            }
          else if (!info->relocatable)
          else if (!info->relocatable)
            {
            {
              if (! ((*info->callbacks->undefined_symbol)
              if (! ((*info->callbacks->undefined_symbol)
                     (info, h->root.root.root.string, input_bfd,
                     (info, h->root.root.root.string, input_bfd,
                      input_section, rel->r_offset,
                      input_section, rel->r_offset,
                      (info->unresolved_syms_in_objects == RM_GENERATE_ERROR)
                      (info->unresolved_syms_in_objects == RM_GENERATE_ERROR)
                      || ELF_ST_VISIBILITY (h->root.other))))
                      || ELF_ST_VISIBILITY (h->root.other))))
                return bfd_reloc_undefined;
                return bfd_reloc_undefined;
              relocation = 0;
              relocation = 0;
            }
            }
        }
        }
 
 
      if (sec != NULL && elf_discarded_section (sec))
      if (sec != NULL && elf_discarded_section (sec))
        {
        {
          /* For relocs against symbols from removed linkonce sections,
          /* For relocs against symbols from removed linkonce sections,
             or sections discarded by a linker script, we just want the
             or sections discarded by a linker script, we just want the
             section contents zeroed.  Avoid any special processing.  */
             section contents zeroed.  Avoid any special processing.  */
          _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
          _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
          rel->r_info = 0;
          rel->r_info = 0;
          rel->r_addend = 0;
          rel->r_addend = 0;
          continue;
          continue;
        }
        }
 
 
      if (info->relocatable)
      if (info->relocatable)
        {
        {
          /* This is a relocatable link.  We don't have to change
          /* This is a relocatable link.  We don't have to change
             anything, unless the reloc is against a section symbol,
             anything, unless the reloc is against a section symbol,
             in which case we have to adjust according to where the
             in which case we have to adjust according to where the
             section symbol winds up in the output section.  */
             section symbol winds up in the output section.  */
          if (r_symndx < symtab_hdr->sh_info)
          if (r_symndx < symtab_hdr->sh_info)
            {
            {
              sym = local_syms + r_symndx;
              sym = local_syms + r_symndx;
              if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
              if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
                {
                {
                  sec = local_sections[r_symndx];
                  sec = local_sections[r_symndx];
                  score_elf_add_to_rel (input_bfd, contents + rel->r_offset,
                  score_elf_add_to_rel (input_bfd, contents + rel->r_offset,
                                    howto, (bfd_signed_vma) (sec->output_offset + sym->st_value));
                                    howto, (bfd_signed_vma) (sec->output_offset + sym->st_value));
                }
                }
            }
            }
          continue;
          continue;
        }
        }
 
 
      /* This is a final link.  */
      /* This is a final link.  */
      r = score_elf_final_link_relocate (howto, input_bfd, output_bfd,
      r = score_elf_final_link_relocate (howto, input_bfd, output_bfd,
                                         input_section, contents, rel, relocs,
                                         input_section, contents, rel, relocs,
                                         relocation, info, name,
                                         relocation, info, name,
                                         (h ? ELF_ST_TYPE ((unsigned int)h->root.root.type) :
                                         (h ? ELF_ST_TYPE ((unsigned int)h->root.root.type) :
                                         ELF_ST_TYPE ((unsigned int)sym->st_info)), h, local_sections,
                                         ELF_ST_TYPE ((unsigned int)sym->st_info)), h, local_sections,
                                         gp_disp_p);
                                         gp_disp_p);
 
 
      if (r != bfd_reloc_ok)
      if (r != bfd_reloc_ok)
        {
        {
          const char *msg = (const char *)0;
          const char *msg = (const char *)0;
 
 
          switch (r)
          switch (r)
            {
            {
            case bfd_reloc_overflow:
            case bfd_reloc_overflow:
              /* If the overflowing reloc was to an undefined symbol,
              /* If the overflowing reloc was to an undefined symbol,
                 we have already printed one error message and there
                 we have already printed one error message and there
                 is no point complaining again.  */
                 is no point complaining again.  */
              if (((!h) || (h->root.root.type != bfd_link_hash_undefined))
              if (((!h) || (h->root.root.type != bfd_link_hash_undefined))
                  && (!((*info->callbacks->reloc_overflow)
                  && (!((*info->callbacks->reloc_overflow)
                        (info, NULL, name, howto->name, (bfd_vma) 0,
                        (info, NULL, name, howto->name, (bfd_vma) 0,
                         input_bfd, input_section, rel->r_offset))))
                         input_bfd, input_section, rel->r_offset))))
                return FALSE;
                return FALSE;
              break;
              break;
            case bfd_reloc_undefined:
            case bfd_reloc_undefined:
              if (!((*info->callbacks->undefined_symbol)
              if (!((*info->callbacks->undefined_symbol)
                    (info, name, input_bfd, input_section, rel->r_offset, TRUE)))
                    (info, name, input_bfd, input_section, rel->r_offset, TRUE)))
                return FALSE;
                return FALSE;
              break;
              break;
 
 
            case bfd_reloc_outofrange:
            case bfd_reloc_outofrange:
              msg = _("internal error: out of range error");
              msg = _("internal error: out of range error");
              goto common_error;
              goto common_error;
 
 
            case bfd_reloc_notsupported:
            case bfd_reloc_notsupported:
              msg = _("internal error: unsupported relocation error");
              msg = _("internal error: unsupported relocation error");
              goto common_error;
              goto common_error;
 
 
            case bfd_reloc_dangerous:
            case bfd_reloc_dangerous:
              msg = _("internal error: dangerous error");
              msg = _("internal error: dangerous error");
              goto common_error;
              goto common_error;
 
 
            /* Use bfd_reloc_other to check lw48, sw48 word align.  */
            /* Use bfd_reloc_other to check lw48, sw48 word align.  */
            case bfd_reloc_other:
            case bfd_reloc_other:
              msg = _("address not word align");
              msg = _("address not word align");
              goto common_error;
              goto common_error;
 
 
            default:
            default:
              msg = _("internal error: unknown error");
              msg = _("internal error: unknown error");
              /* fall through */
              /* fall through */
 
 
            common_error:
            common_error:
              if (!((*info->callbacks->warning)
              if (!((*info->callbacks->warning)
                    (info, msg, name, input_bfd, input_section, rel->r_offset)))
                    (info, msg, name, input_bfd, input_section, rel->r_offset)))
                return FALSE;
                return FALSE;
              break;
              break;
            }
            }
        }
        }
    }
    }
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* Look through the relocs for a section during the first phase, and
/* Look through the relocs for a section during the first phase, and
   allocate space in the global offset table.  */
   allocate space in the global offset table.  */
static bfd_boolean
static bfd_boolean
s3_bfd_score_elf_check_relocs (bfd *abfd,
s3_bfd_score_elf_check_relocs (bfd *abfd,
                               struct bfd_link_info *info,
                               struct bfd_link_info *info,
                               asection *sec,
                               asection *sec,
                               const Elf_Internal_Rela *relocs)
                               const Elf_Internal_Rela *relocs)
{
{
  const char *name;
  const char *name;
  bfd *dynobj;
  bfd *dynobj;
  Elf_Internal_Shdr *symtab_hdr;
  Elf_Internal_Shdr *symtab_hdr;
  struct elf_link_hash_entry **sym_hashes;
  struct elf_link_hash_entry **sym_hashes;
  struct score_got_info *g;
  struct score_got_info *g;
  size_t extsymoff;
  size_t extsymoff;
  const Elf_Internal_Rela *rel;
  const Elf_Internal_Rela *rel;
  const Elf_Internal_Rela *rel_end;
  const Elf_Internal_Rela *rel_end;
  asection *sgot;
  asection *sgot;
  asection *sreloc;
  asection *sreloc;
  const struct elf_backend_data *bed;
  const struct elf_backend_data *bed;
 
 
  if (info->relocatable)
  if (info->relocatable)
    return TRUE;
    return TRUE;
 
 
  dynobj = elf_hash_table (info)->dynobj;
  dynobj = elf_hash_table (info)->dynobj;
  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
  sym_hashes = elf_sym_hashes (abfd);
  sym_hashes = elf_sym_hashes (abfd);
  extsymoff = (elf_bad_symtab (abfd)) ? 0 : symtab_hdr->sh_info;
  extsymoff = (elf_bad_symtab (abfd)) ? 0 : symtab_hdr->sh_info;
 
 
  name = bfd_get_section_name (abfd, sec);
  name = bfd_get_section_name (abfd, sec);
 
 
  if (dynobj == NULL)
  if (dynobj == NULL)
    {
    {
      sgot = NULL;
      sgot = NULL;
      g = NULL;
      g = NULL;
    }
    }
  else
  else
    {
    {
      sgot = score_elf_got_section (dynobj, FALSE);
      sgot = score_elf_got_section (dynobj, FALSE);
      if (sgot == NULL)
      if (sgot == NULL)
        g = NULL;
        g = NULL;
      else
      else
        {
        {
          BFD_ASSERT (score_elf_section_data (sgot) != NULL);
          BFD_ASSERT (score_elf_section_data (sgot) != NULL);
          g = score_elf_section_data (sgot)->u.got_info;
          g = score_elf_section_data (sgot)->u.got_info;
          BFD_ASSERT (g != NULL);
          BFD_ASSERT (g != NULL);
        }
        }
    }
    }
 
 
  sreloc = NULL;
  sreloc = NULL;
  bed = get_elf_backend_data (abfd);
  bed = get_elf_backend_data (abfd);
  rel_end = relocs + sec->reloc_count * bed->s->int_rels_per_ext_rel;
  rel_end = relocs + sec->reloc_count * bed->s->int_rels_per_ext_rel;
  for (rel = relocs; rel < rel_end; ++rel)
  for (rel = relocs; rel < rel_end; ++rel)
    {
    {
      unsigned long r_symndx;
      unsigned long r_symndx;
      unsigned int r_type;
      unsigned int r_type;
      struct elf_link_hash_entry *h;
      struct elf_link_hash_entry *h;
 
 
      r_symndx = ELF32_R_SYM (rel->r_info);
      r_symndx = ELF32_R_SYM (rel->r_info);
      r_type = ELF32_R_TYPE (rel->r_info);
      r_type = ELF32_R_TYPE (rel->r_info);
 
 
      if (r_symndx < extsymoff)
      if (r_symndx < extsymoff)
        {
        {
          h = NULL;
          h = NULL;
        }
        }
      else if (r_symndx >= extsymoff + NUM_SHDR_ENTRIES (symtab_hdr))
      else if (r_symndx >= extsymoff + NUM_SHDR_ENTRIES (symtab_hdr))
        {
        {
          (*_bfd_error_handler) (_("%s: Malformed reloc detected for section %s"), abfd, name);
          (*_bfd_error_handler) (_("%s: Malformed reloc detected for section %s"), abfd, name);
          bfd_set_error (bfd_error_bad_value);
          bfd_set_error (bfd_error_bad_value);
          return FALSE;
          return FALSE;
        }
        }
      else
      else
        {
        {
          h = sym_hashes[r_symndx - extsymoff];
          h = sym_hashes[r_symndx - extsymoff];
 
 
          /* This may be an indirect symbol created because of a version.  */
          /* This may be an indirect symbol created because of a version.  */
          if (h != NULL)
          if (h != NULL)
            {
            {
              while (h->root.type == bfd_link_hash_indirect)
              while (h->root.type == bfd_link_hash_indirect)
                h = (struct elf_link_hash_entry *)h->root.u.i.link;
                h = (struct elf_link_hash_entry *)h->root.u.i.link;
            }
            }
        }
        }
 
 
      /* Some relocs require a global offset table.  */
      /* Some relocs require a global offset table.  */
      if (dynobj == NULL || sgot == NULL)
      if (dynobj == NULL || sgot == NULL)
        {
        {
          switch (r_type)
          switch (r_type)
            {
            {
            case R_SCORE_GOT15:
            case R_SCORE_GOT15:
            case R_SCORE_CALL15:
            case R_SCORE_CALL15:
              if (dynobj == NULL)
              if (dynobj == NULL)
                elf_hash_table (info)->dynobj = dynobj = abfd;
                elf_hash_table (info)->dynobj = dynobj = abfd;
              if (!score_elf_create_got_section (dynobj, info, FALSE))
              if (!score_elf_create_got_section (dynobj, info, FALSE))
                return FALSE;
                return FALSE;
              g = score_elf_got_info (dynobj, &sgot);
              g = score_elf_got_info (dynobj, &sgot);
              break;
              break;
            case R_SCORE_ABS32:
            case R_SCORE_ABS32:
            case R_SCORE_REL32:
            case R_SCORE_REL32:
              if (dynobj == NULL && (info->shared || h != NULL) && (sec->flags & SEC_ALLOC) != 0)
              if (dynobj == NULL && (info->shared || h != NULL) && (sec->flags & SEC_ALLOC) != 0)
                elf_hash_table (info)->dynobj = dynobj = abfd;
                elf_hash_table (info)->dynobj = dynobj = abfd;
              break;
              break;
            default:
            default:
              break;
              break;
            }
            }
        }
        }
 
 
      if (!h && (r_type == R_SCORE_GOT_LO16))
      if (!h && (r_type == R_SCORE_GOT_LO16))
        {
        {
          if (! score_elf_record_local_got_symbol (abfd, r_symndx, rel->r_addend, g))
          if (! score_elf_record_local_got_symbol (abfd, r_symndx, rel->r_addend, g))
            return FALSE;
            return FALSE;
        }
        }
 
 
      switch (r_type)
      switch (r_type)
        {
        {
        case R_SCORE_CALL15:
        case R_SCORE_CALL15:
          if (h == NULL)
          if (h == NULL)
            {
            {
              (*_bfd_error_handler)
              (*_bfd_error_handler)
                (_("%B: CALL15 reloc at 0x%lx not against global symbol"),
                (_("%B: CALL15 reloc at 0x%lx not against global symbol"),
                 abfd, (unsigned long) rel->r_offset);
                 abfd, (unsigned long) rel->r_offset);
              bfd_set_error (bfd_error_bad_value);
              bfd_set_error (bfd_error_bad_value);
              return FALSE;
              return FALSE;
            }
            }
          else
          else
            {
            {
              /* This symbol requires a global offset table entry.  */
              /* This symbol requires a global offset table entry.  */
              if (! score_elf_record_global_got_symbol (h, abfd, info, g))
              if (! score_elf_record_global_got_symbol (h, abfd, info, g))
                return FALSE;
                return FALSE;
 
 
              /* We need a stub, not a plt entry for the undefined function.  But we record
              /* We need a stub, not a plt entry for the undefined function.  But we record
                 it as if it needs plt.  See _bfd_elf_adjust_dynamic_symbol.  */
                 it as if it needs plt.  See _bfd_elf_adjust_dynamic_symbol.  */
              h->needs_plt = 1;
              h->needs_plt = 1;
              h->type = STT_FUNC;
              h->type = STT_FUNC;
            }
            }
          break;
          break;
        case R_SCORE_GOT15:
        case R_SCORE_GOT15:
          if (h && ! score_elf_record_global_got_symbol (h, abfd, info, g))
          if (h && ! score_elf_record_global_got_symbol (h, abfd, info, g))
            return FALSE;
            return FALSE;
          break;
          break;
        case R_SCORE_ABS32:
        case R_SCORE_ABS32:
        case R_SCORE_REL32:
        case R_SCORE_REL32:
          if ((info->shared || h != NULL) && (sec->flags & SEC_ALLOC) != 0)
          if ((info->shared || h != NULL) && (sec->flags & SEC_ALLOC) != 0)
            {
            {
              if (sreloc == NULL)
              if (sreloc == NULL)
                {
                {
                  sreloc = score_elf_rel_dyn_section (dynobj, TRUE);
                  sreloc = score_elf_rel_dyn_section (dynobj, TRUE);
                  if (sreloc == NULL)
                  if (sreloc == NULL)
                    return FALSE;
                    return FALSE;
                }
                }
#define SCORE_READONLY_SECTION (SEC_ALLOC | SEC_LOAD | SEC_READONLY)
#define SCORE_READONLY_SECTION (SEC_ALLOC | SEC_LOAD | SEC_READONLY)
              if (info->shared)
              if (info->shared)
                {
                {
                  /* When creating a shared object, we must copy these reloc types into
                  /* When creating a shared object, we must copy these reloc types into
                     the output file as R_SCORE_REL32 relocs.  We make room for this reloc
                     the output file as R_SCORE_REL32 relocs.  We make room for this reloc
                     in the .rel.dyn reloc section.  */
                     in the .rel.dyn reloc section.  */
                  score_elf_allocate_dynamic_relocations (dynobj, 1);
                  score_elf_allocate_dynamic_relocations (dynobj, 1);
                  if ((sec->flags & SCORE_READONLY_SECTION)
                  if ((sec->flags & SCORE_READONLY_SECTION)
                      == SCORE_READONLY_SECTION)
                      == SCORE_READONLY_SECTION)
                    /* We tell the dynamic linker that there are
                    /* We tell the dynamic linker that there are
                       relocations against the text segment.  */
                       relocations against the text segment.  */
                    info->flags |= DF_TEXTREL;
                    info->flags |= DF_TEXTREL;
                }
                }
              else
              else
                {
                {
                  struct score_elf_link_hash_entry *hscore;
                  struct score_elf_link_hash_entry *hscore;
 
 
                  /* We only need to copy this reloc if the symbol is
                  /* We only need to copy this reloc if the symbol is
                     defined in a dynamic object.  */
                     defined in a dynamic object.  */
                  hscore = (struct score_elf_link_hash_entry *)h;
                  hscore = (struct score_elf_link_hash_entry *)h;
                  ++hscore->possibly_dynamic_relocs;
                  ++hscore->possibly_dynamic_relocs;
                  if ((sec->flags & SCORE_READONLY_SECTION)
                  if ((sec->flags & SCORE_READONLY_SECTION)
                      == SCORE_READONLY_SECTION)
                      == SCORE_READONLY_SECTION)
                    /* We need it to tell the dynamic linker if there
                    /* We need it to tell the dynamic linker if there
                       are relocations against the text segment.  */
                       are relocations against the text segment.  */
                    hscore->readonly_reloc = TRUE;
                    hscore->readonly_reloc = TRUE;
                }
                }
 
 
              /* Even though we don't directly need a GOT entry for this symbol,
              /* Even though we don't directly need a GOT entry for this symbol,
                 a symbol must have a dynamic symbol table index greater that
                 a symbol must have a dynamic symbol table index greater that
                 DT_SCORE_GOTSYM if there are dynamic relocations against it.  */
                 DT_SCORE_GOTSYM if there are dynamic relocations against it.  */
              if (h != NULL)
              if (h != NULL)
                {
                {
                  if (dynobj == NULL)
                  if (dynobj == NULL)
                    elf_hash_table (info)->dynobj = dynobj = abfd;
                    elf_hash_table (info)->dynobj = dynobj = abfd;
                  if (! score_elf_create_got_section (dynobj, info, TRUE))
                  if (! score_elf_create_got_section (dynobj, info, TRUE))
                    return FALSE;
                    return FALSE;
                  g = score_elf_got_info (dynobj, &sgot);
                  g = score_elf_got_info (dynobj, &sgot);
                  if (! score_elf_record_global_got_symbol (h, abfd, info, g))
                  if (! score_elf_record_global_got_symbol (h, abfd, info, g))
                    return FALSE;
                    return FALSE;
                }
                }
            }
            }
          break;
          break;
 
 
          /* This relocation describes the C++ object vtable hierarchy.
          /* This relocation describes the C++ object vtable hierarchy.
             Reconstruct it for later use during GC.  */
             Reconstruct it for later use during GC.  */
        case R_SCORE_GNU_VTINHERIT:
        case R_SCORE_GNU_VTINHERIT:
          if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
          if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
            return FALSE;
            return FALSE;
          break;
          break;
 
 
          /* This relocation describes which C++ vtable entries are actually
          /* This relocation describes which C++ vtable entries are actually
             used.  Record for later use during GC.  */
             used.  Record for later use during GC.  */
        case R_SCORE_GNU_VTENTRY:
        case R_SCORE_GNU_VTENTRY:
          if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset))
          if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset))
            return FALSE;
            return FALSE;
          break;
          break;
        default:
        default:
          break;
          break;
        }
        }
 
 
      /* We must not create a stub for a symbol that has relocations
      /* We must not create a stub for a symbol that has relocations
         related to taking the function's address.  */
         related to taking the function's address.  */
      switch (r_type)
      switch (r_type)
        {
        {
        default:
        default:
          if (h != NULL)
          if (h != NULL)
            {
            {
              struct score_elf_link_hash_entry *sh;
              struct score_elf_link_hash_entry *sh;
 
 
              sh = (struct score_elf_link_hash_entry *) h;
              sh = (struct score_elf_link_hash_entry *) h;
              sh->no_fn_stub = TRUE;
              sh->no_fn_stub = TRUE;
            }
            }
          break;
          break;
        case R_SCORE_CALL15:
        case R_SCORE_CALL15:
          break;
          break;
        }
        }
    }
    }
 
 
  return TRUE;
  return TRUE;
}
}
 
 
static bfd_boolean
static bfd_boolean
s3_bfd_score_elf_add_symbol_hook (bfd *abfd,
s3_bfd_score_elf_add_symbol_hook (bfd *abfd,
                                  struct bfd_link_info *info ATTRIBUTE_UNUSED,
                                  struct bfd_link_info *info ATTRIBUTE_UNUSED,
                                  Elf_Internal_Sym *sym,
                                  Elf_Internal_Sym *sym,
                                  const char **namep ATTRIBUTE_UNUSED,
                                  const char **namep ATTRIBUTE_UNUSED,
                                  flagword *flagsp ATTRIBUTE_UNUSED,
                                  flagword *flagsp ATTRIBUTE_UNUSED,
                                  asection **secp,
                                  asection **secp,
                                  bfd_vma *valp)
                                  bfd_vma *valp)
{
{
  switch (sym->st_shndx)
  switch (sym->st_shndx)
    {
    {
    case SHN_COMMON:
    case SHN_COMMON:
      if (sym->st_size > elf_gp_size (abfd))
      if (sym->st_size > elf_gp_size (abfd))
        break;
        break;
      /* Fall through.  */
      /* Fall through.  */
    case SHN_SCORE_SCOMMON:
    case SHN_SCORE_SCOMMON:
      *secp = bfd_make_section_old_way (abfd, ".scommon");
      *secp = bfd_make_section_old_way (abfd, ".scommon");
      (*secp)->flags |= SEC_IS_COMMON;
      (*secp)->flags |= SEC_IS_COMMON;
      *valp = sym->st_size;
      *valp = sym->st_size;
      break;
      break;
    }
    }
 
 
  return TRUE;
  return TRUE;
}
}
 
 
static void
static void
s3_bfd_score_elf_symbol_processing (bfd *abfd, asymbol *asym)
s3_bfd_score_elf_symbol_processing (bfd *abfd, asymbol *asym)
{
{
  elf_symbol_type *elfsym;
  elf_symbol_type *elfsym;
 
 
  elfsym = (elf_symbol_type *) asym;
  elfsym = (elf_symbol_type *) asym;
  switch (elfsym->internal_elf_sym.st_shndx)
  switch (elfsym->internal_elf_sym.st_shndx)
    {
    {
    case SHN_COMMON:
    case SHN_COMMON:
      if (asym->value > elf_gp_size (abfd))
      if (asym->value > elf_gp_size (abfd))
        break;
        break;
      /* Fall through.  */
      /* Fall through.  */
    case SHN_SCORE_SCOMMON:
    case SHN_SCORE_SCOMMON:
      if (score_elf_scom_section.name == NULL)
      if (score_elf_scom_section.name == NULL)
        {
        {
          /* Initialize the small common section.  */
          /* Initialize the small common section.  */
          score_elf_scom_section.name = ".scommon";
          score_elf_scom_section.name = ".scommon";
          score_elf_scom_section.flags = SEC_IS_COMMON;
          score_elf_scom_section.flags = SEC_IS_COMMON;
          score_elf_scom_section.output_section = &score_elf_scom_section;
          score_elf_scom_section.output_section = &score_elf_scom_section;
          score_elf_scom_section.symbol = &score_elf_scom_symbol;
          score_elf_scom_section.symbol = &score_elf_scom_symbol;
          score_elf_scom_section.symbol_ptr_ptr = &score_elf_scom_symbol_ptr;
          score_elf_scom_section.symbol_ptr_ptr = &score_elf_scom_symbol_ptr;
          score_elf_scom_symbol.name = ".scommon";
          score_elf_scom_symbol.name = ".scommon";
          score_elf_scom_symbol.flags = BSF_SECTION_SYM;
          score_elf_scom_symbol.flags = BSF_SECTION_SYM;
          score_elf_scom_symbol.section = &score_elf_scom_section;
          score_elf_scom_symbol.section = &score_elf_scom_section;
          score_elf_scom_symbol_ptr = &score_elf_scom_symbol;
          score_elf_scom_symbol_ptr = &score_elf_scom_symbol;
        }
        }
      asym->section = &score_elf_scom_section;
      asym->section = &score_elf_scom_section;
      asym->value = elfsym->internal_elf_sym.st_size;
      asym->value = elfsym->internal_elf_sym.st_size;
      break;
      break;
    }
    }
}
}
 
 
static int
static int
s3_bfd_score_elf_link_output_symbol_hook (struct bfd_link_info *info ATTRIBUTE_UNUSED,
s3_bfd_score_elf_link_output_symbol_hook (struct bfd_link_info *info ATTRIBUTE_UNUSED,
                                          const char *name ATTRIBUTE_UNUSED,
                                          const char *name ATTRIBUTE_UNUSED,
                                          Elf_Internal_Sym *sym,
                                          Elf_Internal_Sym *sym,
                                          asection *input_sec,
                                          asection *input_sec,
                                          struct elf_link_hash_entry *h ATTRIBUTE_UNUSED)
                                          struct elf_link_hash_entry *h ATTRIBUTE_UNUSED)
{
{
  /* If we see a common symbol, which implies a relocatable link, then
  /* If we see a common symbol, which implies a relocatable link, then
     if a symbol was small common in an input file, mark it as small
     if a symbol was small common in an input file, mark it as small
     common in the output file.  */
     common in the output file.  */
  if (sym->st_shndx == SHN_COMMON && strcmp (input_sec->name, ".scommon") == 0)
  if (sym->st_shndx == SHN_COMMON && strcmp (input_sec->name, ".scommon") == 0)
    sym->st_shndx = SHN_SCORE_SCOMMON;
    sym->st_shndx = SHN_SCORE_SCOMMON;
 
 
  return 1;
  return 1;
}
}
 
 
static bfd_boolean
static bfd_boolean
s3_bfd_score_elf_section_from_bfd_section (bfd *abfd ATTRIBUTE_UNUSED,
s3_bfd_score_elf_section_from_bfd_section (bfd *abfd ATTRIBUTE_UNUSED,
                                           asection *sec,
                                           asection *sec,
                                           int *retval)
                                           int *retval)
{
{
  if (strcmp (bfd_get_section_name (abfd, sec), ".scommon") == 0)
  if (strcmp (bfd_get_section_name (abfd, sec), ".scommon") == 0)
    {
    {
      *retval = SHN_SCORE_SCOMMON;
      *retval = SHN_SCORE_SCOMMON;
      return TRUE;
      return TRUE;
    }
    }
 
 
  return FALSE;
  return FALSE;
}
}
 
 
/* Adjust a symbol defined by a dynamic object and referenced by a
/* Adjust a symbol defined by a dynamic object and referenced by a
   regular object.  The current definition is in some section of the
   regular object.  The current definition is in some section of the
   dynamic object, but we're not including those sections.  We have to
   dynamic object, but we're not including those sections.  We have to
   change the definition to something the rest of the link can understand.  */
   change the definition to something the rest of the link can understand.  */
static bfd_boolean
static bfd_boolean
s3_bfd_score_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
s3_bfd_score_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
                                        struct elf_link_hash_entry *h)
                                        struct elf_link_hash_entry *h)
{
{
  bfd *dynobj;
  bfd *dynobj;
  struct score_elf_link_hash_entry *hscore;
  struct score_elf_link_hash_entry *hscore;
  asection *s;
  asection *s;
 
 
  dynobj = elf_hash_table (info)->dynobj;
  dynobj = elf_hash_table (info)->dynobj;
 
 
  /* Make sure we know what is going on here.  */
  /* Make sure we know what is going on here.  */
  BFD_ASSERT (dynobj != NULL
  BFD_ASSERT (dynobj != NULL
              && (h->needs_plt
              && (h->needs_plt
                  || h->u.weakdef != NULL
                  || h->u.weakdef != NULL
                  || (h->def_dynamic && h->ref_regular && !h->def_regular)));
                  || (h->def_dynamic && h->ref_regular && !h->def_regular)));
 
 
  /* If this symbol is defined in a dynamic object, we need to copy
  /* If this symbol is defined in a dynamic object, we need to copy
     any R_SCORE_ABS32 or R_SCORE_REL32 relocs against it into the output
     any R_SCORE_ABS32 or R_SCORE_REL32 relocs against it into the output
     file.  */
     file.  */
  hscore = (struct score_elf_link_hash_entry *)h;
  hscore = (struct score_elf_link_hash_entry *)h;
  if (!info->relocatable
  if (!info->relocatable
      && hscore->possibly_dynamic_relocs != 0
      && hscore->possibly_dynamic_relocs != 0
      && (h->root.type == bfd_link_hash_defweak || !h->def_regular))
      && (h->root.type == bfd_link_hash_defweak || !h->def_regular))
    {
    {
      score_elf_allocate_dynamic_relocations (dynobj, hscore->possibly_dynamic_relocs);
      score_elf_allocate_dynamic_relocations (dynobj, hscore->possibly_dynamic_relocs);
      if (hscore->readonly_reloc)
      if (hscore->readonly_reloc)
        /* We tell the dynamic linker that there are relocations
        /* We tell the dynamic linker that there are relocations
           against the text segment.  */
           against the text segment.  */
        info->flags |= DF_TEXTREL;
        info->flags |= DF_TEXTREL;
    }
    }
 
 
  /* For a function, create a stub, if allowed.  */
  /* For a function, create a stub, if allowed.  */
  if (!hscore->no_fn_stub && h->needs_plt)
  if (!hscore->no_fn_stub && h->needs_plt)
    {
    {
      if (!elf_hash_table (info)->dynamic_sections_created)
      if (!elf_hash_table (info)->dynamic_sections_created)
        return TRUE;
        return TRUE;
 
 
      /* If this symbol is not defined in a regular file, then set
      /* If this symbol is not defined in a regular file, then set
         the symbol to the stub location.  This is required to make
         the symbol to the stub location.  This is required to make
         function pointers compare as equal between the normal
         function pointers compare as equal between the normal
         executable and the shared library.  */
         executable and the shared library.  */
      if (!h->def_regular)
      if (!h->def_regular)
        {
        {
          /* We need .stub section.  */
          /* We need .stub section.  */
          s = bfd_get_section_by_name (dynobj, SCORE_ELF_STUB_SECTION_NAME);
          s = bfd_get_section_by_name (dynobj, SCORE_ELF_STUB_SECTION_NAME);
          BFD_ASSERT (s != NULL);
          BFD_ASSERT (s != NULL);
 
 
          h->root.u.def.section = s;
          h->root.u.def.section = s;
          h->root.u.def.value = s->size;
          h->root.u.def.value = s->size;
 
 
          /* XXX Write this stub address somewhere.  */
          /* XXX Write this stub address somewhere.  */
          h->plt.offset = s->size;
          h->plt.offset = s->size;
 
 
          /* Make room for this stub code.  */
          /* Make room for this stub code.  */
          s->size += SCORE_FUNCTION_STUB_SIZE;
          s->size += SCORE_FUNCTION_STUB_SIZE;
 
 
          /* The last half word of the stub will be filled with the index
          /* The last half word of the stub will be filled with the index
             of this symbol in .dynsym section.  */
             of this symbol in .dynsym section.  */
          return TRUE;
          return TRUE;
        }
        }
    }
    }
  else if ((h->type == STT_FUNC) && !h->needs_plt)
  else if ((h->type == STT_FUNC) && !h->needs_plt)
    {
    {
      /* This will set the entry for this symbol in the GOT to 0, and
      /* This will set the entry for this symbol in the GOT to 0, and
         the dynamic linker will take care of this.  */
         the dynamic linker will take care of this.  */
      h->root.u.def.value = 0;
      h->root.u.def.value = 0;
      return TRUE;
      return TRUE;
    }
    }
 
 
  /* If this is a weak symbol, and there is a real definition, the
  /* If this is a weak symbol, and there is a real definition, the
     processor independent code will have arranged for us to see the
     processor independent code will have arranged for us to see the
     real definition first, and we can just use the same value.  */
     real definition first, and we can just use the same value.  */
  if (h->u.weakdef != NULL)
  if (h->u.weakdef != NULL)
    {
    {
      BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined
      BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined
                  || h->u.weakdef->root.type == bfd_link_hash_defweak);
                  || h->u.weakdef->root.type == bfd_link_hash_defweak);
      h->root.u.def.section = h->u.weakdef->root.u.def.section;
      h->root.u.def.section = h->u.weakdef->root.u.def.section;
      h->root.u.def.value = h->u.weakdef->root.u.def.value;
      h->root.u.def.value = h->u.weakdef->root.u.def.value;
      return TRUE;
      return TRUE;
    }
    }
 
 
  /* This is a reference to a symbol defined by a dynamic object which
  /* This is a reference to a symbol defined by a dynamic object which
     is not a function.  */
     is not a function.  */
  return TRUE;
  return TRUE;
}
}
 
 
/* This function is called after all the input files have been read,
/* This function is called after all the input files have been read,
   and the input sections have been assigned to output sections.  */
   and the input sections have been assigned to output sections.  */
static bfd_boolean
static bfd_boolean
s3_bfd_score_elf_always_size_sections (bfd *output_bfd,
s3_bfd_score_elf_always_size_sections (bfd *output_bfd,
                                       struct bfd_link_info *info)
                                       struct bfd_link_info *info)
{
{
  bfd *dynobj;
  bfd *dynobj;
  asection *s;
  asection *s;
  struct score_got_info *g;
  struct score_got_info *g;
  int i;
  int i;
  bfd_size_type loadable_size = 0;
  bfd_size_type loadable_size = 0;
  bfd_size_type local_gotno;
  bfd_size_type local_gotno;
  bfd *sub;
  bfd *sub;
 
 
  dynobj = elf_hash_table (info)->dynobj;
  dynobj = elf_hash_table (info)->dynobj;
  if (dynobj == NULL)
  if (dynobj == NULL)
    /* Relocatable links don't have it.  */
    /* Relocatable links don't have it.  */
    return TRUE;
    return TRUE;
 
 
  g = score_elf_got_info (dynobj, &s);
  g = score_elf_got_info (dynobj, &s);
  if (s == NULL)
  if (s == NULL)
    return TRUE;
    return TRUE;
 
 
  /* Calculate the total loadable size of the output.  That will give us the
  /* Calculate the total loadable size of the output.  That will give us the
     maximum number of GOT_PAGE entries required.  */
     maximum number of GOT_PAGE entries required.  */
  for (sub = info->input_bfds; sub; sub = sub->link_next)
  for (sub = info->input_bfds; sub; sub = sub->link_next)
    {
    {
      asection *subsection;
      asection *subsection;
 
 
      for (subsection = sub->sections;
      for (subsection = sub->sections;
           subsection;
           subsection;
           subsection = subsection->next)
           subsection = subsection->next)
        {
        {
          if ((subsection->flags & SEC_ALLOC) == 0)
          if ((subsection->flags & SEC_ALLOC) == 0)
            continue;
            continue;
          loadable_size += ((subsection->size + 0xf)
          loadable_size += ((subsection->size + 0xf)
                            &~ (bfd_size_type) 0xf);
                            &~ (bfd_size_type) 0xf);
        }
        }
    }
    }
 
 
  /* There has to be a global GOT entry for every symbol with
  /* There has to be a global GOT entry for every symbol with
     a dynamic symbol table index of DT_SCORE_GOTSYM or
     a dynamic symbol table index of DT_SCORE_GOTSYM or
     higher.  Therefore, it make sense to put those symbols
     higher.  Therefore, it make sense to put those symbols
     that need GOT entries at the end of the symbol table.  We
     that need GOT entries at the end of the symbol table.  We
     do that here.  */
     do that here.  */
  if (! score_elf_sort_hash_table (info, 1))
  if (! score_elf_sort_hash_table (info, 1))
    return FALSE;
    return FALSE;
 
 
  if (g->global_gotsym != NULL)
  if (g->global_gotsym != NULL)
    i = elf_hash_table (info)->dynsymcount - g->global_gotsym->dynindx;
    i = elf_hash_table (info)->dynsymcount - g->global_gotsym->dynindx;
  else
  else
    /* If there are no global symbols, or none requiring
    /* If there are no global symbols, or none requiring
       relocations, then GLOBAL_GOTSYM will be NULL.  */
       relocations, then GLOBAL_GOTSYM will be NULL.  */
    i = 0;
    i = 0;
 
 
  /* In the worst case, we'll get one stub per dynamic symbol.  */
  /* In the worst case, we'll get one stub per dynamic symbol.  */
  loadable_size += SCORE_FUNCTION_STUB_SIZE * i;
  loadable_size += SCORE_FUNCTION_STUB_SIZE * i;
 
 
  /* Assume there are two loadable segments consisting of
  /* Assume there are two loadable segments consisting of
     contiguous sections.  Is 5 enough?  */
     contiguous sections.  Is 5 enough?  */
  local_gotno = (loadable_size >> 16) + 5;
  local_gotno = (loadable_size >> 16) + 5;
 
 
  g->local_gotno += local_gotno;
  g->local_gotno += local_gotno;
  s->size += g->local_gotno * SCORE_ELF_GOT_SIZE (output_bfd);
  s->size += g->local_gotno * SCORE_ELF_GOT_SIZE (output_bfd);
 
 
  g->global_gotno = i;
  g->global_gotno = i;
  s->size += i * SCORE_ELF_GOT_SIZE (output_bfd);
  s->size += i * SCORE_ELF_GOT_SIZE (output_bfd);
 
 
  score_elf_resolve_final_got_entries (g);
  score_elf_resolve_final_got_entries (g);
 
 
  if (s->size > SCORE_ELF_GOT_MAX_SIZE (output_bfd))
  if (s->size > SCORE_ELF_GOT_MAX_SIZE (output_bfd))
    {
    {
      /* Fixme. Error message or Warning message should be issued here.  */
      /* Fixme. Error message or Warning message should be issued here.  */
    }
    }
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* Set the sizes of the dynamic sections.  */
/* Set the sizes of the dynamic sections.  */
static bfd_boolean
static bfd_boolean
s3_bfd_score_elf_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
s3_bfd_score_elf_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
{
{
  bfd *dynobj;
  bfd *dynobj;
  asection *s;
  asection *s;
  bfd_boolean reltext;
  bfd_boolean reltext;
 
 
  dynobj = elf_hash_table (info)->dynobj;
  dynobj = elf_hash_table (info)->dynobj;
  BFD_ASSERT (dynobj != NULL);
  BFD_ASSERT (dynobj != NULL);
 
 
  if (elf_hash_table (info)->dynamic_sections_created)
  if (elf_hash_table (info)->dynamic_sections_created)
    {
    {
      /* Set the contents of the .interp section to the interpreter.  */
      /* Set the contents of the .interp section to the interpreter.  */
      if (!info->shared)
      if (!info->shared)
        {
        {
          s = bfd_get_section_by_name (dynobj, ".interp");
          s = bfd_get_section_by_name (dynobj, ".interp");
          BFD_ASSERT (s != NULL);
          BFD_ASSERT (s != NULL);
          s->size = strlen (ELF_DYNAMIC_INTERPRETER) + 1;
          s->size = strlen (ELF_DYNAMIC_INTERPRETER) + 1;
          s->contents = (bfd_byte *) ELF_DYNAMIC_INTERPRETER;
          s->contents = (bfd_byte *) ELF_DYNAMIC_INTERPRETER;
        }
        }
    }
    }
 
 
  /* The check_relocs and adjust_dynamic_symbol entry points have
  /* The check_relocs and adjust_dynamic_symbol entry points have
     determined the sizes of the various dynamic sections.  Allocate
     determined the sizes of the various dynamic sections.  Allocate
     memory for them.  */
     memory for them.  */
  reltext = FALSE;
  reltext = FALSE;
  for (s = dynobj->sections; s != NULL; s = s->next)
  for (s = dynobj->sections; s != NULL; s = s->next)
    {
    {
      const char *name;
      const char *name;
 
 
      if ((s->flags & SEC_LINKER_CREATED) == 0)
      if ((s->flags & SEC_LINKER_CREATED) == 0)
        continue;
        continue;
 
 
      /* It's OK to base decisions on the section name, because none
      /* It's OK to base decisions on the section name, because none
         of the dynobj section names depend upon the input files.  */
         of the dynobj section names depend upon the input files.  */
      name = bfd_get_section_name (dynobj, s);
      name = bfd_get_section_name (dynobj, s);
 
 
      if (CONST_STRNEQ (name, ".rel"))
      if (CONST_STRNEQ (name, ".rel"))
        {
        {
          if (s->size == 0)
          if (s->size == 0)
            {
            {
              /* We only strip the section if the output section name
              /* We only strip the section if the output section name
                 has the same name.  Otherwise, there might be several
                 has the same name.  Otherwise, there might be several
                 input sections for this output section.  FIXME: This
                 input sections for this output section.  FIXME: This
                 code is probably not needed these days anyhow, since
                 code is probably not needed these days anyhow, since
                 the linker now does not create empty output sections.  */
                 the linker now does not create empty output sections.  */
              if (s->output_section != NULL
              if (s->output_section != NULL
                  && strcmp (name,
                  && strcmp (name,
                             bfd_get_section_name (s->output_section->owner,
                             bfd_get_section_name (s->output_section->owner,
                                                   s->output_section)) == 0)
                                                   s->output_section)) == 0)
                s->flags |= SEC_EXCLUDE;
                s->flags |= SEC_EXCLUDE;
            }
            }
          else
          else
            {
            {
              const char *outname;
              const char *outname;
              asection *target;
              asection *target;
 
 
              /* If this relocation section applies to a read only
              /* If this relocation section applies to a read only
                 section, then we probably need a DT_TEXTREL entry.
                 section, then we probably need a DT_TEXTREL entry.
                 If the relocation section is .rel.dyn, we always
                 If the relocation section is .rel.dyn, we always
                 assert a DT_TEXTREL entry rather than testing whether
                 assert a DT_TEXTREL entry rather than testing whether
                 there exists a relocation to a read only section or
                 there exists a relocation to a read only section or
                 not.  */
                 not.  */
              outname = bfd_get_section_name (output_bfd, s->output_section);
              outname = bfd_get_section_name (output_bfd, s->output_section);
              target = bfd_get_section_by_name (output_bfd, outname + 4);
              target = bfd_get_section_by_name (output_bfd, outname + 4);
              if ((target != NULL
              if ((target != NULL
                   && (target->flags & SEC_READONLY) != 0
                   && (target->flags & SEC_READONLY) != 0
                   && (target->flags & SEC_ALLOC) != 0) || strcmp (outname, ".rel.dyn") == 0)
                   && (target->flags & SEC_ALLOC) != 0) || strcmp (outname, ".rel.dyn") == 0)
                reltext = TRUE;
                reltext = TRUE;
 
 
              /* We use the reloc_count field as a counter if we need
              /* We use the reloc_count field as a counter if we need
                 to copy relocs into the output file.  */
                 to copy relocs into the output file.  */
              if (strcmp (name, ".rel.dyn") != 0)
              if (strcmp (name, ".rel.dyn") != 0)
                s->reloc_count = 0;
                s->reloc_count = 0;
            }
            }
        }
        }
      else if (CONST_STRNEQ (name, ".got"))
      else if (CONST_STRNEQ (name, ".got"))
        {
        {
          /* s3_bfd_score_elf_always_size_sections() has already done
          /* s3_bfd_score_elf_always_size_sections() has already done
             most of the work, but some symbols may have been mapped
             most of the work, but some symbols may have been mapped
             to versions that we must now resolve in the got_entries
             to versions that we must now resolve in the got_entries
             hash tables.  */
             hash tables.  */
        }
        }
      else if (strcmp (name, SCORE_ELF_STUB_SECTION_NAME) == 0)
      else if (strcmp (name, SCORE_ELF_STUB_SECTION_NAME) == 0)
        {
        {
          /* IRIX rld assumes that the function stub isn't at the end
          /* IRIX rld assumes that the function stub isn't at the end
             of .text section. So put a dummy. XXX  */
             of .text section. So put a dummy. XXX  */
          s->size += SCORE_FUNCTION_STUB_SIZE;
          s->size += SCORE_FUNCTION_STUB_SIZE;
        }
        }
      else if (! CONST_STRNEQ (name, ".init"))
      else if (! CONST_STRNEQ (name, ".init"))
        {
        {
          /* It's not one of our sections, so don't allocate space.  */
          /* It's not one of our sections, so don't allocate space.  */
          continue;
          continue;
        }
        }
 
 
      /* Allocate memory for the section contents.  */
      /* Allocate memory for the section contents.  */
      s->contents = bfd_zalloc (dynobj, s->size);
      s->contents = bfd_zalloc (dynobj, s->size);
      if (s->contents == NULL && s->size != 0)
      if (s->contents == NULL && s->size != 0)
        {
        {
          bfd_set_error (bfd_error_no_memory);
          bfd_set_error (bfd_error_no_memory);
          return FALSE;
          return FALSE;
        }
        }
    }
    }
 
 
  if (elf_hash_table (info)->dynamic_sections_created)
  if (elf_hash_table (info)->dynamic_sections_created)
    {
    {
      /* Add some entries to the .dynamic section.  We fill in the
      /* Add some entries to the .dynamic section.  We fill in the
         values later, in s3_bfd_score_elf_finish_dynamic_sections, but we
         values later, in s3_bfd_score_elf_finish_dynamic_sections, but we
         must add the entries now so that we get the correct size for
         must add the entries now so that we get the correct size for
         the .dynamic section.  The DT_DEBUG entry is filled in by the
         the .dynamic section.  The DT_DEBUG entry is filled in by the
         dynamic linker and used by the debugger.  */
         dynamic linker and used by the debugger.  */
 
 
      if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_DEBUG, 0))
      if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_DEBUG, 0))
        return FALSE;
        return FALSE;
 
 
      if (reltext)
      if (reltext)
        info->flags |= DF_TEXTREL;
        info->flags |= DF_TEXTREL;
 
 
      if ((info->flags & DF_TEXTREL) != 0)
      if ((info->flags & DF_TEXTREL) != 0)
        {
        {
          if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_TEXTREL, 0))
          if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_TEXTREL, 0))
            return FALSE;
            return FALSE;
        }
        }
 
 
      if (! SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_PLTGOT, 0))
      if (! SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_PLTGOT, 0))
        return FALSE;
        return FALSE;
 
 
      if (score_elf_rel_dyn_section (dynobj, FALSE))
      if (score_elf_rel_dyn_section (dynobj, FALSE))
        {
        {
          if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_REL, 0))
          if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_REL, 0))
            return FALSE;
            return FALSE;
 
 
          if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_RELSZ, 0))
          if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_RELSZ, 0))
            return FALSE;
            return FALSE;
 
 
          if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_RELENT, 0))
          if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_RELENT, 0))
            return FALSE;
            return FALSE;
        }
        }
 
 
      if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_BASE_ADDRESS, 0))
      if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_BASE_ADDRESS, 0))
        return FALSE;
        return FALSE;
 
 
      if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_LOCAL_GOTNO, 0))
      if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_LOCAL_GOTNO, 0))
        return FALSE;
        return FALSE;
 
 
      if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_SYMTABNO, 0))
      if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_SYMTABNO, 0))
        return FALSE;
        return FALSE;
 
 
      if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_UNREFEXTNO, 0))
      if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_UNREFEXTNO, 0))
        return FALSE;
        return FALSE;
 
 
      if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_GOTSYM, 0))
      if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_GOTSYM, 0))
        return FALSE;
        return FALSE;
 
 
      if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_HIPAGENO, 0))
      if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_HIPAGENO, 0))
        return FALSE;
        return FALSE;
    }
    }
 
 
  return TRUE;
  return TRUE;
}
}
 
 
static bfd_boolean
static bfd_boolean
s3_bfd_score_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
s3_bfd_score_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
{
{
  struct elf_link_hash_entry *h;
  struct elf_link_hash_entry *h;
  struct bfd_link_hash_entry *bh;
  struct bfd_link_hash_entry *bh;
  flagword flags;
  flagword flags;
  asection *s;
  asection *s;
 
 
  flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
  flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
           | SEC_LINKER_CREATED | SEC_READONLY);
           | SEC_LINKER_CREATED | SEC_READONLY);
 
 
  /* ABI requests the .dynamic section to be read only.  */
  /* ABI requests the .dynamic section to be read only.  */
  s = bfd_get_section_by_name (abfd, ".dynamic");
  s = bfd_get_section_by_name (abfd, ".dynamic");
  if (s != NULL)
  if (s != NULL)
    {
    {
      if (!bfd_set_section_flags (abfd, s, flags))
      if (!bfd_set_section_flags (abfd, s, flags))
        return FALSE;
        return FALSE;
    }
    }
 
 
  /* We need to create .got section.  */
  /* We need to create .got section.  */
  if (!score_elf_create_got_section (abfd, info, FALSE))
  if (!score_elf_create_got_section (abfd, info, FALSE))
    return FALSE;
    return FALSE;
 
 
  if (!score_elf_rel_dyn_section (elf_hash_table (info)->dynobj, TRUE))
  if (!score_elf_rel_dyn_section (elf_hash_table (info)->dynobj, TRUE))
    return FALSE;
    return FALSE;
 
 
  /* Create .stub section.  */
  /* Create .stub section.  */
  if (bfd_get_section_by_name (abfd, SCORE_ELF_STUB_SECTION_NAME) == NULL)
  if (bfd_get_section_by_name (abfd, SCORE_ELF_STUB_SECTION_NAME) == NULL)
    {
    {
      s = bfd_make_section_with_flags (abfd, SCORE_ELF_STUB_SECTION_NAME,
      s = bfd_make_section_with_flags (abfd, SCORE_ELF_STUB_SECTION_NAME,
                                       flags | SEC_CODE);
                                       flags | SEC_CODE);
      if (s == NULL
      if (s == NULL
          || !bfd_set_section_alignment (abfd, s, 2))
          || !bfd_set_section_alignment (abfd, s, 2))
 
 
        return FALSE;
        return FALSE;
    }
    }
 
 
  if (!info->shared)
  if (!info->shared)
    {
    {
      const char *name;
      const char *name;
 
 
      name = "_DYNAMIC_LINK";
      name = "_DYNAMIC_LINK";
      bh = NULL;
      bh = NULL;
      if (!(_bfd_generic_link_add_one_symbol
      if (!(_bfd_generic_link_add_one_symbol
            (info, abfd, name, BSF_GLOBAL, bfd_abs_section_ptr,
            (info, abfd, name, BSF_GLOBAL, bfd_abs_section_ptr,
             (bfd_vma) 0, NULL, FALSE, get_elf_backend_data (abfd)->collect, &bh)))
             (bfd_vma) 0, NULL, FALSE, get_elf_backend_data (abfd)->collect, &bh)))
        return FALSE;
        return FALSE;
 
 
      h = (struct elf_link_hash_entry *)bh;
      h = (struct elf_link_hash_entry *)bh;
      h->non_elf = 0;
      h->non_elf = 0;
      h->def_regular = 1;
      h->def_regular = 1;
      h->type = STT_SECTION;
      h->type = STT_SECTION;
 
 
      if (!bfd_elf_link_record_dynamic_symbol (info, h))
      if (!bfd_elf_link_record_dynamic_symbol (info, h))
        return FALSE;
        return FALSE;
    }
    }
 
 
  return TRUE;
  return TRUE;
}
}
 
 
 
 
/* Finish up dynamic symbol handling.  We set the contents of various
/* Finish up dynamic symbol handling.  We set the contents of various
   dynamic sections here.  */
   dynamic sections here.  */
static bfd_boolean
static bfd_boolean
s3_bfd_score_elf_finish_dynamic_symbol (bfd *output_bfd,
s3_bfd_score_elf_finish_dynamic_symbol (bfd *output_bfd,
                                        struct bfd_link_info *info,
                                        struct bfd_link_info *info,
                                        struct elf_link_hash_entry *h,
                                        struct elf_link_hash_entry *h,
                                        Elf_Internal_Sym *sym)
                                        Elf_Internal_Sym *sym)
{
{
  bfd *dynobj;
  bfd *dynobj;
  asection *sgot;
  asection *sgot;
  struct score_got_info *g;
  struct score_got_info *g;
  const char *name;
  const char *name;
 
 
  dynobj = elf_hash_table (info)->dynobj;
  dynobj = elf_hash_table (info)->dynobj;
 
 
  if (h->plt.offset != MINUS_ONE)
  if (h->plt.offset != MINUS_ONE)
    {
    {
      asection *s;
      asection *s;
      bfd_byte stub[SCORE_FUNCTION_STUB_SIZE];
      bfd_byte stub[SCORE_FUNCTION_STUB_SIZE];
 
 
      /* This symbol has a stub.  Set it up.  */
      /* This symbol has a stub.  Set it up.  */
      BFD_ASSERT (h->dynindx != -1);
      BFD_ASSERT (h->dynindx != -1);
 
 
      s = bfd_get_section_by_name (dynobj, SCORE_ELF_STUB_SECTION_NAME);
      s = bfd_get_section_by_name (dynobj, SCORE_ELF_STUB_SECTION_NAME);
      BFD_ASSERT (s != NULL);
      BFD_ASSERT (s != NULL);
 
 
      /* FIXME: Can h->dynindex be more than 64K?  */
      /* FIXME: Can h->dynindex be more than 64K?  */
      if (h->dynindx & 0xffff0000)
      if (h->dynindx & 0xffff0000)
        return FALSE;
        return FALSE;
 
 
      /* Fill the stub.  */
      /* Fill the stub.  */
      score_bfd_put_32 (output_bfd, STUB_LW, stub);
      score_bfd_put_32 (output_bfd, STUB_LW, stub);
      score_bfd_put_32 (output_bfd, STUB_MOVE, stub + 4);
      score_bfd_put_32 (output_bfd, STUB_MOVE, stub + 4);
      score_bfd_put_32 (output_bfd, STUB_LI16 | (h->dynindx << 1), stub + 8);
      score_bfd_put_32 (output_bfd, STUB_LI16 | (h->dynindx << 1), stub + 8);
      score_bfd_put_32 (output_bfd, STUB_BRL, stub + 12);
      score_bfd_put_32 (output_bfd, STUB_BRL, stub + 12);
 
 
      BFD_ASSERT (h->plt.offset <= s->size);
      BFD_ASSERT (h->plt.offset <= s->size);
      memcpy (s->contents + h->plt.offset, stub, SCORE_FUNCTION_STUB_SIZE);
      memcpy (s->contents + h->plt.offset, stub, SCORE_FUNCTION_STUB_SIZE);
 
 
      /* Mark the symbol as undefined.  plt.offset != -1 occurs
      /* Mark the symbol as undefined.  plt.offset != -1 occurs
         only for the referenced symbol.  */
         only for the referenced symbol.  */
      sym->st_shndx = SHN_UNDEF;
      sym->st_shndx = SHN_UNDEF;
 
 
      /* The run-time linker uses the st_value field of the symbol
      /* The run-time linker uses the st_value field of the symbol
          to reset the global offset table entry for this external
          to reset the global offset table entry for this external
          to its stub address when unlinking a shared object.  */
          to its stub address when unlinking a shared object.  */
      sym->st_value = (s->output_section->vma + s->output_offset + h->plt.offset);
      sym->st_value = (s->output_section->vma + s->output_offset + h->plt.offset);
    }
    }
 
 
  BFD_ASSERT (h->dynindx != -1 || h->forced_local);
  BFD_ASSERT (h->dynindx != -1 || h->forced_local);
 
 
  sgot = score_elf_got_section (dynobj, FALSE);
  sgot = score_elf_got_section (dynobj, FALSE);
  BFD_ASSERT (sgot != NULL);
  BFD_ASSERT (sgot != NULL);
  BFD_ASSERT (score_elf_section_data (sgot) != NULL);
  BFD_ASSERT (score_elf_section_data (sgot) != NULL);
  g = score_elf_section_data (sgot)->u.got_info;
  g = score_elf_section_data (sgot)->u.got_info;
  BFD_ASSERT (g != NULL);
  BFD_ASSERT (g != NULL);
 
 
  /* Run through the global symbol table, creating GOT entries for all
  /* Run through the global symbol table, creating GOT entries for all
     the symbols that need them.  */
     the symbols that need them.  */
  if (g->global_gotsym != NULL && h->dynindx >= g->global_gotsym->dynindx)
  if (g->global_gotsym != NULL && h->dynindx >= g->global_gotsym->dynindx)
    {
    {
      bfd_vma offset;
      bfd_vma offset;
      bfd_vma value;
      bfd_vma value;
 
 
      value = sym->st_value;
      value = sym->st_value;
      offset = score_elf_global_got_index (dynobj, h);
      offset = score_elf_global_got_index (dynobj, h);
      score_bfd_put_32 (output_bfd, value, sgot->contents + offset);
      score_bfd_put_32 (output_bfd, value, sgot->contents + offset);
    }
    }
 
 
  /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute.  */
  /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute.  */
  name = h->root.root.string;
  name = h->root.root.string;
  if (strcmp (name, "_DYNAMIC") == 0 || strcmp (name, "_GLOBAL_OFFSET_TABLE_") == 0)
  if (strcmp (name, "_DYNAMIC") == 0 || strcmp (name, "_GLOBAL_OFFSET_TABLE_") == 0)
    sym->st_shndx = SHN_ABS;
    sym->st_shndx = SHN_ABS;
  else if (strcmp (name, "_DYNAMIC_LINK") == 0)
  else if (strcmp (name, "_DYNAMIC_LINK") == 0)
    {
    {
      sym->st_shndx = SHN_ABS;
      sym->st_shndx = SHN_ABS;
      sym->st_info = ELF_ST_INFO (STB_GLOBAL, STT_SECTION);
      sym->st_info = ELF_ST_INFO (STB_GLOBAL, STT_SECTION);
      sym->st_value = 1;
      sym->st_value = 1;
    }
    }
  else if (strcmp (name, GP_DISP_LABEL) == 0)
  else if (strcmp (name, GP_DISP_LABEL) == 0)
    {
    {
      sym->st_shndx = SHN_ABS;
      sym->st_shndx = SHN_ABS;
      sym->st_info = ELF_ST_INFO (STB_GLOBAL, STT_SECTION);
      sym->st_info = ELF_ST_INFO (STB_GLOBAL, STT_SECTION);
      sym->st_value = elf_gp (output_bfd);
      sym->st_value = elf_gp (output_bfd);
    }
    }
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* Finish up the dynamic sections.  */
/* Finish up the dynamic sections.  */
static bfd_boolean
static bfd_boolean
s3_bfd_score_elf_finish_dynamic_sections (bfd *output_bfd,
s3_bfd_score_elf_finish_dynamic_sections (bfd *output_bfd,
                                          struct bfd_link_info *info)
                                          struct bfd_link_info *info)
{
{
  bfd *dynobj;
  bfd *dynobj;
  asection *sdyn;
  asection *sdyn;
  asection *sgot;
  asection *sgot;
  asection *s;
  asection *s;
  struct score_got_info *g;
  struct score_got_info *g;
 
 
  dynobj = elf_hash_table (info)->dynobj;
  dynobj = elf_hash_table (info)->dynobj;
 
 
  sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
  sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
 
 
  sgot = score_elf_got_section (dynobj, FALSE);
  sgot = score_elf_got_section (dynobj, FALSE);
  if (sgot == NULL)
  if (sgot == NULL)
    g = NULL;
    g = NULL;
  else
  else
    {
    {
      BFD_ASSERT (score_elf_section_data (sgot) != NULL);
      BFD_ASSERT (score_elf_section_data (sgot) != NULL);
      g = score_elf_section_data (sgot)->u.got_info;
      g = score_elf_section_data (sgot)->u.got_info;
      BFD_ASSERT (g != NULL);
      BFD_ASSERT (g != NULL);
    }
    }
 
 
  if (elf_hash_table (info)->dynamic_sections_created)
  if (elf_hash_table (info)->dynamic_sections_created)
    {
    {
      bfd_byte *b;
      bfd_byte *b;
 
 
      BFD_ASSERT (sdyn != NULL);
      BFD_ASSERT (sdyn != NULL);
      BFD_ASSERT (g != NULL);
      BFD_ASSERT (g != NULL);
 
 
      for (b = sdyn->contents;
      for (b = sdyn->contents;
           b < sdyn->contents + sdyn->size;
           b < sdyn->contents + sdyn->size;
           b += SCORE_ELF_DYN_SIZE (dynobj))
           b += SCORE_ELF_DYN_SIZE (dynobj))
        {
        {
          Elf_Internal_Dyn dyn;
          Elf_Internal_Dyn dyn;
          const char *name;
          const char *name;
          size_t elemsize;
          size_t elemsize;
          bfd_boolean swap_out_p;
          bfd_boolean swap_out_p;
 
 
          /* Read in the current dynamic entry.  */
          /* Read in the current dynamic entry.  */
          (*get_elf_backend_data (dynobj)->s->swap_dyn_in) (dynobj, b, &dyn);
          (*get_elf_backend_data (dynobj)->s->swap_dyn_in) (dynobj, b, &dyn);
 
 
          /* Assume that we're going to modify it and write it out.  */
          /* Assume that we're going to modify it and write it out.  */
          swap_out_p = TRUE;
          swap_out_p = TRUE;
 
 
          switch (dyn.d_tag)
          switch (dyn.d_tag)
            {
            {
            case DT_RELENT:
            case DT_RELENT:
              s = score_elf_rel_dyn_section (dynobj, FALSE);
              s = score_elf_rel_dyn_section (dynobj, FALSE);
              BFD_ASSERT (s != NULL);
              BFD_ASSERT (s != NULL);
              dyn.d_un.d_val = SCORE_ELF_REL_SIZE (dynobj);
              dyn.d_un.d_val = SCORE_ELF_REL_SIZE (dynobj);
              break;
              break;
 
 
            case DT_STRSZ:
            case DT_STRSZ:
              /* Rewrite DT_STRSZ.  */
              /* Rewrite DT_STRSZ.  */
              dyn.d_un.d_val = _bfd_elf_strtab_size (elf_hash_table (info)->dynstr);
              dyn.d_un.d_val = _bfd_elf_strtab_size (elf_hash_table (info)->dynstr);
                    break;
                    break;
 
 
            case DT_PLTGOT:
            case DT_PLTGOT:
              name = ".got";
              name = ".got";
              s = bfd_get_section_by_name (output_bfd, name);
              s = bfd_get_section_by_name (output_bfd, name);
              BFD_ASSERT (s != NULL);
              BFD_ASSERT (s != NULL);
              dyn.d_un.d_ptr = s->vma;
              dyn.d_un.d_ptr = s->vma;
              break;
              break;
 
 
            case DT_SCORE_BASE_ADDRESS:
            case DT_SCORE_BASE_ADDRESS:
              s = output_bfd->sections;
              s = output_bfd->sections;
              BFD_ASSERT (s != NULL);
              BFD_ASSERT (s != NULL);
              dyn.d_un.d_ptr = s->vma & ~(bfd_vma) 0xffff;
              dyn.d_un.d_ptr = s->vma & ~(bfd_vma) 0xffff;
              break;
              break;
 
 
            case DT_SCORE_LOCAL_GOTNO:
            case DT_SCORE_LOCAL_GOTNO:
              dyn.d_un.d_val = g->local_gotno;
              dyn.d_un.d_val = g->local_gotno;
              break;
              break;
 
 
            case DT_SCORE_UNREFEXTNO:
            case DT_SCORE_UNREFEXTNO:
              /* The index into the dynamic symbol table which is the
              /* The index into the dynamic symbol table which is the
                 entry of the first external symbol that is not
                 entry of the first external symbol that is not
                 referenced within the same object.  */
                 referenced within the same object.  */
              dyn.d_un.d_val = bfd_count_sections (output_bfd) + 1;
              dyn.d_un.d_val = bfd_count_sections (output_bfd) + 1;
              break;
              break;
 
 
            case DT_SCORE_GOTSYM:
            case DT_SCORE_GOTSYM:
              if (g->global_gotsym)
              if (g->global_gotsym)
                {
                {
                  dyn.d_un.d_val = g->global_gotsym->dynindx;
                  dyn.d_un.d_val = g->global_gotsym->dynindx;
                  break;
                  break;
                }
                }
              /* In case if we don't have global got symbols we default
              /* In case if we don't have global got symbols we default
                  to setting DT_SCORE_GOTSYM to the same value as
                  to setting DT_SCORE_GOTSYM to the same value as
                  DT_SCORE_SYMTABNO, so we just fall through.  */
                  DT_SCORE_SYMTABNO, so we just fall through.  */
 
 
            case DT_SCORE_SYMTABNO:
            case DT_SCORE_SYMTABNO:
              name = ".dynsym";
              name = ".dynsym";
              elemsize = SCORE_ELF_SYM_SIZE (output_bfd);
              elemsize = SCORE_ELF_SYM_SIZE (output_bfd);
              s = bfd_get_section_by_name (output_bfd, name);
              s = bfd_get_section_by_name (output_bfd, name);
              BFD_ASSERT (s != NULL);
              BFD_ASSERT (s != NULL);
 
 
              dyn.d_un.d_val = s->size / elemsize;
              dyn.d_un.d_val = s->size / elemsize;
              break;
              break;
 
 
            case DT_SCORE_HIPAGENO:
            case DT_SCORE_HIPAGENO:
              dyn.d_un.d_val = g->local_gotno - SCORE_RESERVED_GOTNO;
              dyn.d_un.d_val = g->local_gotno - SCORE_RESERVED_GOTNO;
              break;
              break;
 
 
            default:
            default:
              swap_out_p = FALSE;
              swap_out_p = FALSE;
              break;
              break;
            }
            }
 
 
          if (swap_out_p)
          if (swap_out_p)
            (*get_elf_backend_data (dynobj)->s->swap_dyn_out) (dynobj, &dyn, b);
            (*get_elf_backend_data (dynobj)->s->swap_dyn_out) (dynobj, &dyn, b);
        }
        }
    }
    }
 
 
  /* The first entry of the global offset table will be filled at
  /* The first entry of the global offset table will be filled at
     runtime. The second entry will be used by some runtime loaders.
     runtime. The second entry will be used by some runtime loaders.
     This isn't the case of IRIX rld.  */
     This isn't the case of IRIX rld.  */
  if (sgot != NULL && sgot->size > 0)
  if (sgot != NULL && sgot->size > 0)
    {
    {
      score_bfd_put_32 (output_bfd, 0, sgot->contents);
      score_bfd_put_32 (output_bfd, 0, sgot->contents);
      score_bfd_put_32 (output_bfd, 0x80000000, sgot->contents + SCORE_ELF_GOT_SIZE (output_bfd));
      score_bfd_put_32 (output_bfd, 0x80000000, sgot->contents + SCORE_ELF_GOT_SIZE (output_bfd));
    }
    }
 
 
  if (sgot != NULL)
  if (sgot != NULL)
    elf_section_data (sgot->output_section)->this_hdr.sh_entsize
    elf_section_data (sgot->output_section)->this_hdr.sh_entsize
      = SCORE_ELF_GOT_SIZE (output_bfd);
      = SCORE_ELF_GOT_SIZE (output_bfd);
 
 
 
 
  /* We need to sort the entries of the dynamic relocation section.  */
  /* We need to sort the entries of the dynamic relocation section.  */
  s = score_elf_rel_dyn_section (dynobj, FALSE);
  s = score_elf_rel_dyn_section (dynobj, FALSE);
 
 
  if (s != NULL && s->size > (bfd_vma)2 * SCORE_ELF_REL_SIZE (output_bfd))
  if (s != NULL && s->size > (bfd_vma)2 * SCORE_ELF_REL_SIZE (output_bfd))
    {
    {
      reldyn_sorting_bfd = output_bfd;
      reldyn_sorting_bfd = output_bfd;
      qsort ((Elf32_External_Rel *) s->contents + 1, s->reloc_count - 1,
      qsort ((Elf32_External_Rel *) s->contents + 1, s->reloc_count - 1,
             sizeof (Elf32_External_Rel), score_elf_sort_dynamic_relocs);
             sizeof (Elf32_External_Rel), score_elf_sort_dynamic_relocs);
    }
    }
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* This function set up the ELF section header for a BFD section in preparation for writing
/* This function set up the ELF section header for a BFD section in preparation for writing
   it out.  This is where the flags and type fields are set for unusual sections.  */
   it out.  This is where the flags and type fields are set for unusual sections.  */
static bfd_boolean
static bfd_boolean
s3_bfd_score_elf_fake_sections (bfd *abfd ATTRIBUTE_UNUSED,
s3_bfd_score_elf_fake_sections (bfd *abfd ATTRIBUTE_UNUSED,
                                Elf_Internal_Shdr *hdr,
                                Elf_Internal_Shdr *hdr,
                                asection *sec)
                                asection *sec)
{
{
  const char *name;
  const char *name;
 
 
  name = bfd_get_section_name (abfd, sec);
  name = bfd_get_section_name (abfd, sec);
 
 
  if (strcmp (name, ".got") == 0
  if (strcmp (name, ".got") == 0
      || strcmp (name, ".srdata") == 0
      || strcmp (name, ".srdata") == 0
      || strcmp (name, ".sdata") == 0
      || strcmp (name, ".sdata") == 0
      || strcmp (name, ".sbss") == 0)
      || strcmp (name, ".sbss") == 0)
    hdr->sh_flags |= SHF_SCORE_GPREL;
    hdr->sh_flags |= SHF_SCORE_GPREL;
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* This function do additional processing on the ELF section header before writing
/* This function do additional processing on the ELF section header before writing
   it out.  This is used to set the flags and type fields for some sections.  */
   it out.  This is used to set the flags and type fields for some sections.  */
 
 
/* assign_file_positions_except_relocs() check section flag and if it is allocatable,
/* assign_file_positions_except_relocs() check section flag and if it is allocatable,
   warning message will be issued.  backend_fake_section is called before
   warning message will be issued.  backend_fake_section is called before
   assign_file_positions_except_relocs(); backend_section_processing after it.  so, we
   assign_file_positions_except_relocs(); backend_section_processing after it.  so, we
   modify section flag there, but not backend_fake_section.  */
   modify section flag there, but not backend_fake_section.  */
static bfd_boolean
static bfd_boolean
s3_bfd_score_elf_section_processing (bfd *abfd ATTRIBUTE_UNUSED, Elf_Internal_Shdr *hdr)
s3_bfd_score_elf_section_processing (bfd *abfd ATTRIBUTE_UNUSED, Elf_Internal_Shdr *hdr)
{
{
  if (hdr->bfd_section != NULL)
  if (hdr->bfd_section != NULL)
    {
    {
      const char *name = bfd_get_section_name (abfd, hdr->bfd_section);
      const char *name = bfd_get_section_name (abfd, hdr->bfd_section);
 
 
      if (strcmp (name, ".sdata") == 0)
      if (strcmp (name, ".sdata") == 0)
        {
        {
          hdr->sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_SCORE_GPREL;
          hdr->sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_SCORE_GPREL;
          hdr->sh_type = SHT_PROGBITS;
          hdr->sh_type = SHT_PROGBITS;
        }
        }
      else if (strcmp (name, ".sbss") == 0)
      else if (strcmp (name, ".sbss") == 0)
        {
        {
          hdr->sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_SCORE_GPREL;
          hdr->sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_SCORE_GPREL;
          hdr->sh_type = SHT_NOBITS;
          hdr->sh_type = SHT_NOBITS;
        }
        }
      else if (strcmp (name, ".srdata") == 0)
      else if (strcmp (name, ".srdata") == 0)
        {
        {
          hdr->sh_flags |= SHF_ALLOC | SHF_SCORE_GPREL;
          hdr->sh_flags |= SHF_ALLOC | SHF_SCORE_GPREL;
          hdr->sh_type = SHT_PROGBITS;
          hdr->sh_type = SHT_PROGBITS;
        }
        }
    }
    }
 
 
  return TRUE;
  return TRUE;
}
}
 
 
static bfd_boolean
static bfd_boolean
s3_bfd_score_elf_write_section (bfd *output_bfd, asection *sec, bfd_byte *contents)
s3_bfd_score_elf_write_section (bfd *output_bfd, asection *sec, bfd_byte *contents)
{
{
  bfd_byte *to, *from, *end;
  bfd_byte *to, *from, *end;
  int i;
  int i;
 
 
  if (strcmp (sec->name, ".pdr") != 0)
  if (strcmp (sec->name, ".pdr") != 0)
    return FALSE;
    return FALSE;
 
 
  if (score_elf_section_data (sec)->u.tdata == NULL)
  if (score_elf_section_data (sec)->u.tdata == NULL)
    return FALSE;
    return FALSE;
 
 
  to = contents;
  to = contents;
  end = contents + sec->size;
  end = contents + sec->size;
  for (from = contents, i = 0; from < end; from += PDR_SIZE, i++)
  for (from = contents, i = 0; from < end; from += PDR_SIZE, i++)
    {
    {
      if ((score_elf_section_data (sec)->u.tdata)[i] == 1)
      if ((score_elf_section_data (sec)->u.tdata)[i] == 1)
        continue;
        continue;
 
 
      if (to != from)
      if (to != from)
        memcpy (to, from, PDR_SIZE);
        memcpy (to, from, PDR_SIZE);
 
 
      to += PDR_SIZE;
      to += PDR_SIZE;
    }
    }
  bfd_set_section_contents (output_bfd, sec->output_section, contents,
  bfd_set_section_contents (output_bfd, sec->output_section, contents,
                            (file_ptr) sec->output_offset, sec->size);
                            (file_ptr) sec->output_offset, sec->size);
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* Copy data from a SCORE ELF indirect symbol to its direct symbol, hiding the old
/* Copy data from a SCORE ELF indirect symbol to its direct symbol, hiding the old
   indirect symbol.  Process additional relocation information.  */
   indirect symbol.  Process additional relocation information.  */
static void
static void
s3_bfd_score_elf_copy_indirect_symbol (struct bfd_link_info *info,
s3_bfd_score_elf_copy_indirect_symbol (struct bfd_link_info *info,
                                       struct elf_link_hash_entry *dir,
                                       struct elf_link_hash_entry *dir,
                                       struct elf_link_hash_entry *ind)
                                       struct elf_link_hash_entry *ind)
{
{
  struct score_elf_link_hash_entry *dirscore, *indscore;
  struct score_elf_link_hash_entry *dirscore, *indscore;
 
 
  _bfd_elf_link_hash_copy_indirect (info, dir, ind);
  _bfd_elf_link_hash_copy_indirect (info, dir, ind);
 
 
  if (ind->root.type != bfd_link_hash_indirect)
  if (ind->root.type != bfd_link_hash_indirect)
    return;
    return;
 
 
  dirscore = (struct score_elf_link_hash_entry *) dir;
  dirscore = (struct score_elf_link_hash_entry *) dir;
  indscore = (struct score_elf_link_hash_entry *) ind;
  indscore = (struct score_elf_link_hash_entry *) ind;
  dirscore->possibly_dynamic_relocs += indscore->possibly_dynamic_relocs;
  dirscore->possibly_dynamic_relocs += indscore->possibly_dynamic_relocs;
 
 
  if (indscore->readonly_reloc)
  if (indscore->readonly_reloc)
    dirscore->readonly_reloc = TRUE;
    dirscore->readonly_reloc = TRUE;
 
 
  if (indscore->no_fn_stub)
  if (indscore->no_fn_stub)
    dirscore->no_fn_stub = TRUE;
    dirscore->no_fn_stub = TRUE;
}
}
 
 
/* Remove information about discarded functions from other sections which mention them.  */
/* Remove information about discarded functions from other sections which mention them.  */
static bfd_boolean
static bfd_boolean
s3_bfd_score_elf_discard_info (bfd *abfd, struct elf_reloc_cookie *cookie,
s3_bfd_score_elf_discard_info (bfd *abfd, struct elf_reloc_cookie *cookie,
                               struct bfd_link_info *info)
                               struct bfd_link_info *info)
{
{
  asection *o;
  asection *o;
  bfd_boolean ret = FALSE;
  bfd_boolean ret = FALSE;
  unsigned char *tdata;
  unsigned char *tdata;
  size_t i, skip;
  size_t i, skip;
 
 
  o = bfd_get_section_by_name (abfd, ".pdr");
  o = bfd_get_section_by_name (abfd, ".pdr");
  if ((!o) || (o->size == 0) || (o->size % PDR_SIZE != 0)
  if ((!o) || (o->size == 0) || (o->size % PDR_SIZE != 0)
      || (o->output_section != NULL && bfd_is_abs_section (o->output_section)))
      || (o->output_section != NULL && bfd_is_abs_section (o->output_section)))
    return FALSE;
    return FALSE;
 
 
  tdata = bfd_zmalloc (o->size / PDR_SIZE);
  tdata = bfd_zmalloc (o->size / PDR_SIZE);
  if (!tdata)
  if (!tdata)
    return FALSE;
    return FALSE;
 
 
  cookie->rels = _bfd_elf_link_read_relocs (abfd, o, NULL, NULL, info->keep_memory);
  cookie->rels = _bfd_elf_link_read_relocs (abfd, o, NULL, NULL, info->keep_memory);
  if (!cookie->rels)
  if (!cookie->rels)
    {
    {
      free (tdata);
      free (tdata);
      return FALSE;
      return FALSE;
    }
    }
 
 
  cookie->rel = cookie->rels;
  cookie->rel = cookie->rels;
  cookie->relend = cookie->rels + o->reloc_count;
  cookie->relend = cookie->rels + o->reloc_count;
 
 
  for (i = 0, skip = 0; i < o->size; i++)
  for (i = 0, skip = 0; i < o->size; i++)
    {
    {
      if (bfd_elf_reloc_symbol_deleted_p (i * PDR_SIZE, cookie))
      if (bfd_elf_reloc_symbol_deleted_p (i * PDR_SIZE, cookie))
        {
        {
          tdata[i] = 1;
          tdata[i] = 1;
          skip++;
          skip++;
        }
        }
    }
    }
 
 
  if (skip != 0)
  if (skip != 0)
    {
    {
      score_elf_section_data (o)->u.tdata = tdata;
      score_elf_section_data (o)->u.tdata = tdata;
      o->size -= skip * PDR_SIZE;
      o->size -= skip * PDR_SIZE;
      ret = TRUE;
      ret = TRUE;
    }
    }
  else
  else
    free (tdata);
    free (tdata);
 
 
  if (!info->keep_memory)
  if (!info->keep_memory)
    free (cookie->rels);
    free (cookie->rels);
 
 
  return ret;
  return ret;
}
}
 
 
/* Signal that discard_info() has removed the discarded relocations for this section.  */
/* Signal that discard_info() has removed the discarded relocations for this section.  */
static bfd_boolean
static bfd_boolean
s3_bfd_score_elf_ignore_discarded_relocs (asection *sec)
s3_bfd_score_elf_ignore_discarded_relocs (asection *sec)
{
{
  if (strcmp (sec->name, ".pdr") == 0)
  if (strcmp (sec->name, ".pdr") == 0)
    return TRUE;
    return TRUE;
  return FALSE;
  return FALSE;
}
}
 
 
/* Return the section that should be marked against GC for a given
/* Return the section that should be marked against GC for a given
   relocation.  */
   relocation.  */
static asection *
static asection *
s3_bfd_score_elf_gc_mark_hook (asection *sec,
s3_bfd_score_elf_gc_mark_hook (asection *sec,
                               struct bfd_link_info *info,
                               struct bfd_link_info *info,
                               Elf_Internal_Rela *rel,
                               Elf_Internal_Rela *rel,
                               struct elf_link_hash_entry *h,
                               struct elf_link_hash_entry *h,
                               Elf_Internal_Sym *sym)
                               Elf_Internal_Sym *sym)
{
{
  if (h != NULL)
  if (h != NULL)
    switch (ELF32_R_TYPE (rel->r_info))
    switch (ELF32_R_TYPE (rel->r_info))
      {
      {
      case R_SCORE_GNU_VTINHERIT:
      case R_SCORE_GNU_VTINHERIT:
      case R_SCORE_GNU_VTENTRY:
      case R_SCORE_GNU_VTENTRY:
        return NULL;
        return NULL;
      }
      }
 
 
  return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
  return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
}
}
 
 
/* Support for core dump NOTE sections.  */
/* Support for core dump NOTE sections.  */
 
 
static bfd_boolean
static bfd_boolean
s3_bfd_score_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
s3_bfd_score_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
{
{
  int offset;
  int offset;
  unsigned int raw_size;
  unsigned int raw_size;
 
 
  switch (note->descsz)
  switch (note->descsz)
    {
    {
    default:
    default:
      return FALSE;
      return FALSE;
 
 
    case 148:                  /* Linux/Score 32-bit.  */
    case 148:                  /* Linux/Score 32-bit.  */
      /* pr_cursig */
      /* pr_cursig */
      elf_tdata (abfd)->core_signal = score_bfd_get_16 (abfd, note->descdata + 12);
      elf_tdata (abfd)->core_signal = score_bfd_get_16 (abfd, note->descdata + 12);
 
 
      /* pr_pid */
      /* pr_pid */
      elf_tdata (abfd)->core_pid = score_bfd_get_32 (abfd, note->descdata + 24);
      elf_tdata (abfd)->core_pid = score_bfd_get_32 (abfd, note->descdata + 24);
 
 
      /* pr_reg */
      /* pr_reg */
      offset = 72;
      offset = 72;
      raw_size = 72;
      raw_size = 72;
 
 
      break;
      break;
    }
    }
 
 
  /* Make a ".reg/999" section.  */
  /* Make a ".reg/999" section.  */
  return _bfd_elfcore_make_pseudosection (abfd, ".reg", raw_size, note->descpos + offset);
  return _bfd_elfcore_make_pseudosection (abfd, ".reg", raw_size, note->descpos + offset);
}
}
 
 
static bfd_boolean
static bfd_boolean
s3_bfd_score_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
s3_bfd_score_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
{
{
  switch (note->descsz)
  switch (note->descsz)
    {
    {
    default:
    default:
      return FALSE;
      return FALSE;
 
 
    case 124:                  /* Linux/Score elf_prpsinfo.  */
    case 124:                  /* Linux/Score elf_prpsinfo.  */
      elf_tdata (abfd)->core_program = _bfd_elfcore_strndup (abfd, note->descdata + 28, 16);
      elf_tdata (abfd)->core_program = _bfd_elfcore_strndup (abfd, note->descdata + 28, 16);
      elf_tdata (abfd)->core_command = _bfd_elfcore_strndup (abfd, note->descdata + 44, 80);
      elf_tdata (abfd)->core_command = _bfd_elfcore_strndup (abfd, note->descdata + 44, 80);
    }
    }
 
 
  /* Note that for some reason, a spurious space is tacked
  /* Note that for some reason, a spurious space is tacked
     onto the end of the args in some (at least one anyway)
     onto the end of the args in some (at least one anyway)
     implementations, so strip it off if it exists.  */
     implementations, so strip it off if it exists.  */
 
 
  {
  {
    char *command = elf_tdata (abfd)->core_command;
    char *command = elf_tdata (abfd)->core_command;
    int n = strlen (command);
    int n = strlen (command);
 
 
    if (0 < n && command[n - 1] == ' ')
    if (0 < n && command[n - 1] == ' ')
      command[n - 1] = '\0';
      command[n - 1] = '\0';
  }
  }
 
 
  return TRUE;
  return TRUE;
}
}
 
 
 
 
/* Score BFD functions.  */
/* Score BFD functions.  */
static reloc_howto_type *
static reloc_howto_type *
s3_elf32_score_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, bfd_reloc_code_real_type code)
s3_elf32_score_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, bfd_reloc_code_real_type code)
{
{
  unsigned int i;
  unsigned int i;
 
 
  for (i = 0; i < ARRAY_SIZE (elf32_score_reloc_map); i++)
  for (i = 0; i < ARRAY_SIZE (elf32_score_reloc_map); i++)
    if (elf32_score_reloc_map[i].bfd_reloc_val == code)
    if (elf32_score_reloc_map[i].bfd_reloc_val == code)
      return &elf32_score_howto_table[elf32_score_reloc_map[i].elf_reloc_val];
      return &elf32_score_howto_table[elf32_score_reloc_map[i].elf_reloc_val];
 
 
  return NULL;
  return NULL;
}
}
 
 
static reloc_howto_type *
static reloc_howto_type *
elf32_score_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
elf32_score_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
                               const char *r_name)
                               const char *r_name)
{
{
  unsigned int i;
  unsigned int i;
 
 
  for (i = 0;
  for (i = 0;
       i < (sizeof (elf32_score_howto_table)
       i < (sizeof (elf32_score_howto_table)
            / sizeof (elf32_score_howto_table[0]));
            / sizeof (elf32_score_howto_table[0]));
       i++)
       i++)
    if (elf32_score_howto_table[i].name != NULL
    if (elf32_score_howto_table[i].name != NULL
        && strcasecmp (elf32_score_howto_table[i].name, r_name) == 0)
        && strcasecmp (elf32_score_howto_table[i].name, r_name) == 0)
      return &elf32_score_howto_table[i];
      return &elf32_score_howto_table[i];
 
 
  return NULL;
  return NULL;
}
}
 
 
static bfd_boolean
static bfd_boolean
s3_elf32_score_print_private_bfd_data (bfd *abfd, void * ptr)
s3_elf32_score_print_private_bfd_data (bfd *abfd, void * ptr)
{
{
  FILE *file = (FILE *) ptr;
  FILE *file = (FILE *) ptr;
 
 
  BFD_ASSERT (abfd != NULL && ptr != NULL);
  BFD_ASSERT (abfd != NULL && ptr != NULL);
 
 
  /* Print normal ELF private data.  */
  /* Print normal ELF private data.  */
  _bfd_elf_print_private_bfd_data (abfd, ptr);
  _bfd_elf_print_private_bfd_data (abfd, ptr);
 
 
  /* xgettext:c-format */
  /* xgettext:c-format */
  fprintf (file, _("private flags = %lx:"), elf_elfheader (abfd)->e_flags);
  fprintf (file, _("private flags = %lx:"), elf_elfheader (abfd)->e_flags);
  if (elf_elfheader (abfd)->e_flags & EF_SCORE_PIC)
  if (elf_elfheader (abfd)->e_flags & EF_SCORE_PIC)
    {
    {
      fprintf (file, _(" [pic]"));
      fprintf (file, _(" [pic]"));
    }
    }
  if (elf_elfheader (abfd)->e_flags & EF_SCORE_FIXDEP)
  if (elf_elfheader (abfd)->e_flags & EF_SCORE_FIXDEP)
    {
    {
      fprintf (file, _(" [fix dep]"));
      fprintf (file, _(" [fix dep]"));
    }
    }
  fputc ('\n', file);
  fputc ('\n', file);
 
 
  return TRUE;
  return TRUE;
}
}
 
 
static bfd_boolean
static bfd_boolean
s3_elf32_score_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
s3_elf32_score_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
{
{
  flagword in_flags;
  flagword in_flags;
  flagword out_flags;
  flagword out_flags;
 
 
  if (!_bfd_generic_verify_endian_match (ibfd, obfd))
  if (!_bfd_generic_verify_endian_match (ibfd, obfd))
    return FALSE;
    return FALSE;
 
 
  in_flags  = elf_elfheader (ibfd)->e_flags;
  in_flags  = elf_elfheader (ibfd)->e_flags;
  out_flags = elf_elfheader (obfd)->e_flags;
  out_flags = elf_elfheader (obfd)->e_flags;
 
 
  if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
  if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
    return TRUE;
    return TRUE;
 
 
  in_flags = elf_elfheader (ibfd)->e_flags;
  in_flags = elf_elfheader (ibfd)->e_flags;
  out_flags = elf_elfheader (obfd)->e_flags;
  out_flags = elf_elfheader (obfd)->e_flags;
 
 
  if (! elf_flags_init (obfd))
  if (! elf_flags_init (obfd))
    {
    {
      elf_flags_init (obfd) = TRUE;
      elf_flags_init (obfd) = TRUE;
      elf_elfheader (obfd)->e_flags = in_flags;
      elf_elfheader (obfd)->e_flags = in_flags;
 
 
      if (bfd_get_arch (obfd) == bfd_get_arch (ibfd)
      if (bfd_get_arch (obfd) == bfd_get_arch (ibfd)
          && bfd_get_arch_info (obfd)->the_default)
          && bfd_get_arch_info (obfd)->the_default)
        {
        {
          return bfd_set_arch_mach (obfd, bfd_get_arch (ibfd), bfd_get_mach (ibfd));
          return bfd_set_arch_mach (obfd, bfd_get_arch (ibfd), bfd_get_mach (ibfd));
        }
        }
 
 
      return TRUE;
      return TRUE;
    }
    }
 
 
  if (((in_flags & EF_SCORE_PIC) != 0) != ((out_flags & EF_SCORE_PIC) != 0))
  if (((in_flags & EF_SCORE_PIC) != 0) != ((out_flags & EF_SCORE_PIC) != 0))
    {
    {
      (*_bfd_error_handler) (_("%B: warning: linking PIC files with non-PIC files"), ibfd);
      (*_bfd_error_handler) (_("%B: warning: linking PIC files with non-PIC files"), ibfd);
    }
    }
 
 
  /* FIXME: Maybe dependency fix compatibility should be checked here.  */
  /* FIXME: Maybe dependency fix compatibility should be checked here.  */
 
 
  return TRUE;
  return TRUE;
}
}
 
 
static bfd_boolean
static bfd_boolean
s3_elf32_score_new_section_hook (bfd *abfd, asection *sec)
s3_elf32_score_new_section_hook (bfd *abfd, asection *sec)
{
{
  struct _score_elf_section_data *sdata;
  struct _score_elf_section_data *sdata;
  bfd_size_type amt = sizeof (*sdata);
  bfd_size_type amt = sizeof (*sdata);
 
 
  sdata = bfd_zalloc (abfd, amt);
  sdata = bfd_zalloc (abfd, amt);
  if (sdata == NULL)
  if (sdata == NULL)
    return FALSE;
    return FALSE;
  sec->used_by_bfd = sdata;
  sec->used_by_bfd = sdata;
 
 
  return _bfd_elf_new_section_hook (abfd, sec);
  return _bfd_elf_new_section_hook (abfd, sec);
}
}
 
 
/*****************************************************************************/
/*****************************************************************************/
 
 
/* s3_s7: backend hooks.  */
/* s3_s7: backend hooks.  */
static void
static void
_bfd_score_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED,
_bfd_score_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED,
                          arelent *bfd_reloc,
                          arelent *bfd_reloc,
                          Elf_Internal_Rela *elf_reloc)
                          Elf_Internal_Rela *elf_reloc)
{
{
  if (bfd_get_mach (abfd) == bfd_mach_score3)
  if (bfd_get_mach (abfd) == bfd_mach_score3)
    return s3_bfd_score_info_to_howto (abfd, bfd_reloc, elf_reloc);
    return s3_bfd_score_info_to_howto (abfd, bfd_reloc, elf_reloc);
  else
  else
    return s7_bfd_score_info_to_howto (abfd, bfd_reloc, elf_reloc);
    return s7_bfd_score_info_to_howto (abfd, bfd_reloc, elf_reloc);
}
}
 
 
static bfd_boolean
static bfd_boolean
_bfd_score_elf_relocate_section (bfd *output_bfd,
_bfd_score_elf_relocate_section (bfd *output_bfd,
                                 struct bfd_link_info *info,
                                 struct bfd_link_info *info,
                                 bfd *input_bfd,
                                 bfd *input_bfd,
                                 asection *input_section,
                                 asection *input_section,
                                 bfd_byte *contents,
                                 bfd_byte *contents,
                                 Elf_Internal_Rela *relocs,
                                 Elf_Internal_Rela *relocs,
                                 Elf_Internal_Sym *local_syms,
                                 Elf_Internal_Sym *local_syms,
                                 asection **local_sections)
                                 asection **local_sections)
{
{
  if (bfd_get_mach (output_bfd) == bfd_mach_score3)
  if (bfd_get_mach (output_bfd) == bfd_mach_score3)
    return s3_bfd_score_elf_relocate_section (output_bfd,
    return s3_bfd_score_elf_relocate_section (output_bfd,
             info, input_bfd, input_section, contents, relocs,
             info, input_bfd, input_section, contents, relocs,
             local_syms, local_sections);
             local_syms, local_sections);
  else
  else
    return s7_bfd_score_elf_relocate_section (output_bfd,
    return s7_bfd_score_elf_relocate_section (output_bfd,
             info, input_bfd, input_section, contents, relocs,
             info, input_bfd, input_section, contents, relocs,
             local_syms, local_sections);
             local_syms, local_sections);
}
}
 
 
static bfd_boolean
static bfd_boolean
_bfd_score_elf_check_relocs (bfd *abfd,
_bfd_score_elf_check_relocs (bfd *abfd,
                             struct bfd_link_info *info,
                             struct bfd_link_info *info,
                             asection *sec,
                             asection *sec,
                             const Elf_Internal_Rela *relocs)
                             const Elf_Internal_Rela *relocs)
{
{
  if (bfd_get_mach (abfd) == bfd_mach_score3)
  if (bfd_get_mach (abfd) == bfd_mach_score3)
    return s3_bfd_score_elf_check_relocs (abfd, info, sec, relocs);
    return s3_bfd_score_elf_check_relocs (abfd, info, sec, relocs);
  else
  else
    return s7_bfd_score_elf_check_relocs (abfd, info, sec, relocs);
    return s7_bfd_score_elf_check_relocs (abfd, info, sec, relocs);
}
}
 
 
static bfd_boolean
static bfd_boolean
_bfd_score_elf_add_symbol_hook (bfd *abfd,
_bfd_score_elf_add_symbol_hook (bfd *abfd,
                                struct bfd_link_info *info ATTRIBUTE_UNUSED,
                                struct bfd_link_info *info ATTRIBUTE_UNUSED,
                                Elf_Internal_Sym *sym,
                                Elf_Internal_Sym *sym,
                                const char **namep ATTRIBUTE_UNUSED,
                                const char **namep ATTRIBUTE_UNUSED,
                                flagword *flagsp ATTRIBUTE_UNUSED,
                                flagword *flagsp ATTRIBUTE_UNUSED,
                                asection **secp,
                                asection **secp,
                                bfd_vma *valp)
                                bfd_vma *valp)
{
{
  if (bfd_get_mach (abfd) == bfd_mach_score3)
  if (bfd_get_mach (abfd) == bfd_mach_score3)
    return s3_bfd_score_elf_add_symbol_hook (abfd, info, sym, namep, flagsp,
    return s3_bfd_score_elf_add_symbol_hook (abfd, info, sym, namep, flagsp,
                                             secp, valp);
                                             secp, valp);
  else
  else
    return s7_bfd_score_elf_add_symbol_hook (abfd, info, sym, namep, flagsp,
    return s7_bfd_score_elf_add_symbol_hook (abfd, info, sym, namep, flagsp,
                                             secp, valp);
                                             secp, valp);
}
}
 
 
static void
static void
_bfd_score_elf_symbol_processing (bfd *abfd, asymbol *asym)
_bfd_score_elf_symbol_processing (bfd *abfd, asymbol *asym)
{
{
  if (bfd_get_mach (abfd) == bfd_mach_score3)
  if (bfd_get_mach (abfd) == bfd_mach_score3)
    return s3_bfd_score_elf_symbol_processing (abfd, asym);
    return s3_bfd_score_elf_symbol_processing (abfd, asym);
  else
  else
    return s7_bfd_score_elf_symbol_processing (abfd, asym);
    return s7_bfd_score_elf_symbol_processing (abfd, asym);
}
}
 
 
static int
static int
_bfd_score_elf_link_output_symbol_hook (struct bfd_link_info *info ATTRIBUTE_UNUSED,
_bfd_score_elf_link_output_symbol_hook (struct bfd_link_info *info ATTRIBUTE_UNUSED,
     const char *name ATTRIBUTE_UNUSED,
     const char *name ATTRIBUTE_UNUSED,
     Elf_Internal_Sym *sym,
     Elf_Internal_Sym *sym,
     asection *input_sec,
     asection *input_sec,
     struct elf_link_hash_entry *h ATTRIBUTE_UNUSED)
     struct elf_link_hash_entry *h ATTRIBUTE_UNUSED)
{
{
  /* If link a empty .o, then this filed is NULL.  */
  /* If link a empty .o, then this filed is NULL.  */
  if (info->input_bfds == NULL)
  if (info->input_bfds == NULL)
    {
    {
      /* If we see a common symbol, which implies a relocatable link, then
      /* If we see a common symbol, which implies a relocatable link, then
         if a symbol was small common in an input file, mark it as small
         if a symbol was small common in an input file, mark it as small
         common in the output file.  */
         common in the output file.  */
      if (sym->st_shndx == SHN_COMMON && strcmp (input_sec->name, ".scommon") == 0)
      if (sym->st_shndx == SHN_COMMON && strcmp (input_sec->name, ".scommon") == 0)
        sym->st_shndx = SHN_SCORE_SCOMMON;
        sym->st_shndx = SHN_SCORE_SCOMMON;
      return 1;
      return 1;
    }
    }
 
 
  if (bfd_get_mach (info->input_bfds) == bfd_mach_score3)
  if (bfd_get_mach (info->input_bfds) == bfd_mach_score3)
    return s3_bfd_score_elf_link_output_symbol_hook (info, name, sym, input_sec, h);
    return s3_bfd_score_elf_link_output_symbol_hook (info, name, sym, input_sec, h);
  else
  else
    return s7_bfd_score_elf_link_output_symbol_hook (info, name, sym, input_sec, h);
    return s7_bfd_score_elf_link_output_symbol_hook (info, name, sym, input_sec, h);
}
}
 
 
static bfd_boolean
static bfd_boolean
_bfd_score_elf_section_from_bfd_section (bfd *abfd ATTRIBUTE_UNUSED,
_bfd_score_elf_section_from_bfd_section (bfd *abfd ATTRIBUTE_UNUSED,
                                         asection *sec,
                                         asection *sec,
                                         int *retval)
                                         int *retval)
{
{
  if (bfd_get_mach (abfd) == bfd_mach_score3)
  if (bfd_get_mach (abfd) == bfd_mach_score3)
    return s3_bfd_score_elf_section_from_bfd_section (abfd, sec, retval);
    return s3_bfd_score_elf_section_from_bfd_section (abfd, sec, retval);
  else
  else
    return s7_bfd_score_elf_section_from_bfd_section (abfd, sec, retval);
    return s7_bfd_score_elf_section_from_bfd_section (abfd, sec, retval);
}
}
 
 
static bfd_boolean
static bfd_boolean
_bfd_score_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
_bfd_score_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
                                      struct elf_link_hash_entry *h)
                                      struct elf_link_hash_entry *h)
{
{
  if (bfd_get_mach (info->input_bfds) == bfd_mach_score3)
  if (bfd_get_mach (info->input_bfds) == bfd_mach_score3)
    return s3_bfd_score_elf_adjust_dynamic_symbol (info, h);
    return s3_bfd_score_elf_adjust_dynamic_symbol (info, h);
  else
  else
    return s7_bfd_score_elf_adjust_dynamic_symbol (info, h);
    return s7_bfd_score_elf_adjust_dynamic_symbol (info, h);
}
}
 
 
static bfd_boolean
static bfd_boolean
_bfd_score_elf_always_size_sections (bfd *output_bfd,
_bfd_score_elf_always_size_sections (bfd *output_bfd,
                                     struct bfd_link_info *info)
                                     struct bfd_link_info *info)
{
{
  if (bfd_get_mach (output_bfd) == bfd_mach_score3)
  if (bfd_get_mach (output_bfd) == bfd_mach_score3)
    return s3_bfd_score_elf_always_size_sections (output_bfd, info);
    return s3_bfd_score_elf_always_size_sections (output_bfd, info);
  else
  else
    return s7_bfd_score_elf_always_size_sections (output_bfd, info);
    return s7_bfd_score_elf_always_size_sections (output_bfd, info);
}
}
 
 
static bfd_boolean
static bfd_boolean
_bfd_score_elf_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
_bfd_score_elf_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
{
{
  if (bfd_get_mach (output_bfd) == bfd_mach_score3)
  if (bfd_get_mach (output_bfd) == bfd_mach_score3)
    return s3_bfd_score_elf_size_dynamic_sections (output_bfd, info);
    return s3_bfd_score_elf_size_dynamic_sections (output_bfd, info);
  else
  else
    return s7_bfd_score_elf_size_dynamic_sections (output_bfd, info);
    return s7_bfd_score_elf_size_dynamic_sections (output_bfd, info);
}
}
 
 
static bfd_boolean
static bfd_boolean
_bfd_score_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
_bfd_score_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
{
{
  if (bfd_get_mach (abfd) == bfd_mach_score3)
  if (bfd_get_mach (abfd) == bfd_mach_score3)
    return s3_bfd_score_elf_create_dynamic_sections (abfd, info);
    return s3_bfd_score_elf_create_dynamic_sections (abfd, info);
  else
  else
    return s7_bfd_score_elf_create_dynamic_sections (abfd, info);
    return s7_bfd_score_elf_create_dynamic_sections (abfd, info);
}
}
 
 
static bfd_boolean
static bfd_boolean
_bfd_score_elf_finish_dynamic_symbol (bfd *output_bfd,
_bfd_score_elf_finish_dynamic_symbol (bfd *output_bfd,
                                      struct bfd_link_info *info,
                                      struct bfd_link_info *info,
                                      struct elf_link_hash_entry *h,
                                      struct elf_link_hash_entry *h,
                                      Elf_Internal_Sym *sym)
                                      Elf_Internal_Sym *sym)
{
{
  if (bfd_get_mach (output_bfd) == bfd_mach_score3)
  if (bfd_get_mach (output_bfd) == bfd_mach_score3)
    return s3_bfd_score_elf_finish_dynamic_symbol (output_bfd, info, h, sym);
    return s3_bfd_score_elf_finish_dynamic_symbol (output_bfd, info, h, sym);
  else
  else
    return s7_bfd_score_elf_finish_dynamic_symbol (output_bfd, info, h, sym);
    return s7_bfd_score_elf_finish_dynamic_symbol (output_bfd, info, h, sym);
}
}
 
 
static bfd_boolean
static bfd_boolean
_bfd_score_elf_finish_dynamic_sections (bfd *output_bfd,
_bfd_score_elf_finish_dynamic_sections (bfd *output_bfd,
                                        struct bfd_link_info *info)
                                        struct bfd_link_info *info)
{
{
  if (bfd_get_mach (output_bfd) == bfd_mach_score3)
  if (bfd_get_mach (output_bfd) == bfd_mach_score3)
    return s3_bfd_score_elf_finish_dynamic_sections (output_bfd, info);
    return s3_bfd_score_elf_finish_dynamic_sections (output_bfd, info);
  else
  else
    return s7_bfd_score_elf_finish_dynamic_sections (output_bfd, info);
    return s7_bfd_score_elf_finish_dynamic_sections (output_bfd, info);
}
}
 
 
static bfd_boolean
static bfd_boolean
_bfd_score_elf_fake_sections (bfd *abfd ATTRIBUTE_UNUSED,
_bfd_score_elf_fake_sections (bfd *abfd ATTRIBUTE_UNUSED,
                              Elf_Internal_Shdr *hdr,
                              Elf_Internal_Shdr *hdr,
                              asection *sec)
                              asection *sec)
{
{
  if (bfd_get_mach (abfd) == bfd_mach_score3)
  if (bfd_get_mach (abfd) == bfd_mach_score3)
    return s3_bfd_score_elf_fake_sections (abfd, hdr, sec);
    return s3_bfd_score_elf_fake_sections (abfd, hdr, sec);
  else
  else
    return s7_bfd_score_elf_fake_sections (abfd, hdr, sec);
    return s7_bfd_score_elf_fake_sections (abfd, hdr, sec);
}
}
 
 
static bfd_boolean
static bfd_boolean
_bfd_score_elf_section_processing (bfd *abfd ATTRIBUTE_UNUSED, Elf_Internal_Shdr *hdr)
_bfd_score_elf_section_processing (bfd *abfd ATTRIBUTE_UNUSED, Elf_Internal_Shdr *hdr)
{
{
  if (bfd_get_mach (abfd) == bfd_mach_score3)
  if (bfd_get_mach (abfd) == bfd_mach_score3)
    return s3_bfd_score_elf_section_processing (abfd, hdr);
    return s3_bfd_score_elf_section_processing (abfd, hdr);
  else
  else
    return s7_bfd_score_elf_section_processing (abfd, hdr);
    return s7_bfd_score_elf_section_processing (abfd, hdr);
}
}
 
 
static bfd_boolean
static bfd_boolean
_bfd_score_elf_write_section (bfd *output_bfd,
_bfd_score_elf_write_section (bfd *output_bfd,
                              struct bfd_link_info *link_info ATTRIBUTE_UNUSED,
                              struct bfd_link_info *link_info ATTRIBUTE_UNUSED,
                              asection *sec, bfd_byte *contents)
                              asection *sec, bfd_byte *contents)
{
{
  if (bfd_get_mach (output_bfd) == bfd_mach_score3)
  if (bfd_get_mach (output_bfd) == bfd_mach_score3)
    return s3_bfd_score_elf_write_section (output_bfd, sec, contents);
    return s3_bfd_score_elf_write_section (output_bfd, sec, contents);
  else
  else
    return s7_bfd_score_elf_write_section (output_bfd, sec, contents);
    return s7_bfd_score_elf_write_section (output_bfd, sec, contents);
}
}
 
 
static void
static void
_bfd_score_elf_copy_indirect_symbol (struct bfd_link_info *info,
_bfd_score_elf_copy_indirect_symbol (struct bfd_link_info *info,
                                     struct elf_link_hash_entry *dir,
                                     struct elf_link_hash_entry *dir,
                                     struct elf_link_hash_entry *ind)
                                     struct elf_link_hash_entry *ind)
{
{
  if (bfd_get_mach (info->input_bfds) == bfd_mach_score3)
  if (bfd_get_mach (info->input_bfds) == bfd_mach_score3)
    return s3_bfd_score_elf_copy_indirect_symbol (info, dir, ind);
    return s3_bfd_score_elf_copy_indirect_symbol (info, dir, ind);
  else
  else
    return s7_bfd_score_elf_copy_indirect_symbol (info, dir, ind);
    return s7_bfd_score_elf_copy_indirect_symbol (info, dir, ind);
}
}
 
 
static void
static void
_bfd_score_elf_hide_symbol (struct bfd_link_info *info,
_bfd_score_elf_hide_symbol (struct bfd_link_info *info,
                            struct elf_link_hash_entry *entry,
                            struct elf_link_hash_entry *entry,
                            bfd_boolean force_local)
                            bfd_boolean force_local)
{
{
  if (bfd_get_mach (info->input_bfds) == bfd_mach_score3)
  if (bfd_get_mach (info->input_bfds) == bfd_mach_score3)
    return s3_bfd_score_elf_hide_symbol (info, entry, force_local);
    return s3_bfd_score_elf_hide_symbol (info, entry, force_local);
  else
  else
    return s7_bfd_score_elf_hide_symbol (info, entry, force_local);
    return s7_bfd_score_elf_hide_symbol (info, entry, force_local);
}
}
 
 
static bfd_boolean
static bfd_boolean
_bfd_score_elf_discard_info (bfd *abfd, struct elf_reloc_cookie *cookie,
_bfd_score_elf_discard_info (bfd *abfd, struct elf_reloc_cookie *cookie,
                         struct bfd_link_info *info)
                         struct bfd_link_info *info)
{
{
  if (bfd_get_mach (abfd) == bfd_mach_score3)
  if (bfd_get_mach (abfd) == bfd_mach_score3)
    return s3_bfd_score_elf_discard_info (abfd, cookie, info);
    return s3_bfd_score_elf_discard_info (abfd, cookie, info);
  else
  else
    return s7_bfd_score_elf_discard_info (abfd, cookie, info);
    return s7_bfd_score_elf_discard_info (abfd, cookie, info);
}
}
 
 
static bfd_boolean
static bfd_boolean
_bfd_score_elf_ignore_discarded_relocs (asection *sec)
_bfd_score_elf_ignore_discarded_relocs (asection *sec)
{
{
  if (bfd_get_mach (sec->owner) == bfd_mach_score3)
  if (bfd_get_mach (sec->owner) == bfd_mach_score3)
    return s3_bfd_score_elf_ignore_discarded_relocs (sec);
    return s3_bfd_score_elf_ignore_discarded_relocs (sec);
  else
  else
    return s7_bfd_score_elf_ignore_discarded_relocs (sec);
    return s7_bfd_score_elf_ignore_discarded_relocs (sec);
}
}
 
 
static asection *
static asection *
_bfd_score_elf_gc_mark_hook (asection *sec,
_bfd_score_elf_gc_mark_hook (asection *sec,
                             struct bfd_link_info *info,
                             struct bfd_link_info *info,
                             Elf_Internal_Rela *rel,
                             Elf_Internal_Rela *rel,
                             struct elf_link_hash_entry *h,
                             struct elf_link_hash_entry *h,
                             Elf_Internal_Sym *sym)
                             Elf_Internal_Sym *sym)
{
{
  if (bfd_get_mach (info->input_bfds) == bfd_mach_score3)
  if (bfd_get_mach (info->input_bfds) == bfd_mach_score3)
    return s3_bfd_score_elf_gc_mark_hook (sec, info, rel, h, sym);
    return s3_bfd_score_elf_gc_mark_hook (sec, info, rel, h, sym);
  else
  else
    return s7_bfd_score_elf_gc_mark_hook (sec, info, rel, h, sym);
    return s7_bfd_score_elf_gc_mark_hook (sec, info, rel, h, sym);
}
}
 
 
static bfd_boolean
static bfd_boolean
_bfd_score_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
_bfd_score_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
{
{
  if (bfd_get_mach (abfd) == bfd_mach_score3)
  if (bfd_get_mach (abfd) == bfd_mach_score3)
    return s3_bfd_score_elf_grok_prstatus (abfd, note);
    return s3_bfd_score_elf_grok_prstatus (abfd, note);
  else
  else
    return s7_bfd_score_elf_grok_prstatus (abfd, note);
    return s7_bfd_score_elf_grok_prstatus (abfd, note);
}
}
 
 
static bfd_boolean
static bfd_boolean
_bfd_score_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
_bfd_score_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
{
{
  if (bfd_get_mach (abfd) == bfd_mach_score3)
  if (bfd_get_mach (abfd) == bfd_mach_score3)
    return s3_bfd_score_elf_grok_psinfo (abfd, note);
    return s3_bfd_score_elf_grok_psinfo (abfd, note);
  else
  else
    return s7_bfd_score_elf_grok_psinfo (abfd, note);
    return s7_bfd_score_elf_grok_psinfo (abfd, note);
}
}
 
 
static reloc_howto_type *
static reloc_howto_type *
elf32_score_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, bfd_reloc_code_real_type code)
elf32_score_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, bfd_reloc_code_real_type code)
{
{
  /* s3: NOTE!!!
  /* s3: NOTE!!!
     gas will call elf32_score_reloc_type_lookup, and don't write elf file.
     gas will call elf32_score_reloc_type_lookup, and don't write elf file.
     So just using score3, but we don't know ld will call this or not.
     So just using score3, but we don't know ld will call this or not.
     If so, this way can't work.  */
     If so, this way can't work.  */
 
 
  if (score3)
  if (score3)
    return s3_elf32_score_reloc_type_lookup (abfd, code);
    return s3_elf32_score_reloc_type_lookup (abfd, code);
  else
  else
    return s7_elf32_score_reloc_type_lookup (abfd, code);
    return s7_elf32_score_reloc_type_lookup (abfd, code);
}
}
 
 
/* Create a score elf linker hash table.
/* Create a score elf linker hash table.
   This is a copy of _bfd_elf_link_hash_table_create() except with a
   This is a copy of _bfd_elf_link_hash_table_create() except with a
   different hash table entry creation function.  */
   different hash table entry creation function.  */
 
 
static struct bfd_link_hash_table *
static struct bfd_link_hash_table *
elf32_score_link_hash_table_create (bfd *abfd)
elf32_score_link_hash_table_create (bfd *abfd)
{
{
  struct elf_link_hash_table *ret;
  struct elf_link_hash_table *ret;
  bfd_size_type amt = sizeof (struct elf_link_hash_table);
  bfd_size_type amt = sizeof (struct elf_link_hash_table);
 
 
  ret = (struct elf_link_hash_table *) bfd_malloc (amt);
  ret = (struct elf_link_hash_table *) bfd_malloc (amt);
  if (ret == NULL)
  if (ret == NULL)
    return NULL;
    return NULL;
 
 
  if (!_bfd_elf_link_hash_table_init (ret, abfd, score_elf_link_hash_newfunc,
  if (!_bfd_elf_link_hash_table_init (ret, abfd, score_elf_link_hash_newfunc,
                                      sizeof (struct score_elf_link_hash_entry),
                                      sizeof (struct score_elf_link_hash_entry),
                                      GENERIC_ELF_DATA))
                                      GENERIC_ELF_DATA))
    {
    {
      free (ret);
      free (ret);
      return NULL;
      return NULL;
    }
    }
 
 
  return &ret->root;
  return &ret->root;
}
}
 
 
static bfd_boolean
static bfd_boolean
elf32_score_print_private_bfd_data (bfd *abfd, void * ptr)
elf32_score_print_private_bfd_data (bfd *abfd, void * ptr)
{
{
  if (bfd_get_mach (abfd) == bfd_mach_score3)
  if (bfd_get_mach (abfd) == bfd_mach_score3)
    return s3_elf32_score_print_private_bfd_data (abfd, ptr);
    return s3_elf32_score_print_private_bfd_data (abfd, ptr);
  else
  else
    return s7_elf32_score_print_private_bfd_data (abfd, ptr);
    return s7_elf32_score_print_private_bfd_data (abfd, ptr);
}
}
 
 
static bfd_boolean
static bfd_boolean
elf32_score_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
elf32_score_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
{
{
  if (bfd_get_mach (obfd) == bfd_mach_score3)
  if (bfd_get_mach (obfd) == bfd_mach_score3)
    return s3_elf32_score_merge_private_bfd_data (ibfd, obfd);
    return s3_elf32_score_merge_private_bfd_data (ibfd, obfd);
  else
  else
    return s7_elf32_score_merge_private_bfd_data (ibfd, obfd);
    return s7_elf32_score_merge_private_bfd_data (ibfd, obfd);
}
}
 
 
static bfd_boolean
static bfd_boolean
elf32_score_new_section_hook (bfd *abfd, asection *sec)
elf32_score_new_section_hook (bfd *abfd, asection *sec)
{
{
  if (bfd_get_mach (abfd) == bfd_mach_score3)
  if (bfd_get_mach (abfd) == bfd_mach_score3)
    return s3_elf32_score_new_section_hook (abfd, sec);
    return s3_elf32_score_new_section_hook (abfd, sec);
  else
  else
    return s7_elf32_score_new_section_hook (abfd, sec);
    return s7_elf32_score_new_section_hook (abfd, sec);
}
}
 
 
 
 
/* s3_s7: don't need to split.  */
/* s3_s7: don't need to split.  */
 
 
/* Set the right machine number.  */
/* Set the right machine number.  */
static bfd_boolean
static bfd_boolean
_bfd_score_elf_score_object_p (bfd * abfd)
_bfd_score_elf_score_object_p (bfd * abfd)
{
{
  int e_set = bfd_mach_score7;
  int e_set = bfd_mach_score7;
 
 
  if (elf_elfheader (abfd)->e_machine == EM_SCORE)
  if (elf_elfheader (abfd)->e_machine == EM_SCORE)
    {
    {
      int e_mach = elf_elfheader (abfd)->e_flags & EF_SCORE_MACH & EF_OMIT_PIC_FIXDD;
      int e_mach = elf_elfheader (abfd)->e_flags & EF_SCORE_MACH & EF_OMIT_PIC_FIXDD;
      switch (e_mach)
      switch (e_mach)
        {
        {
        /* Set default target is score7.  */
        /* Set default target is score7.  */
        default:
        default:
        case E_SCORE_MACH_SCORE7:
        case E_SCORE_MACH_SCORE7:
          e_set = bfd_mach_score7;
          e_set = bfd_mach_score7;
          break;
          break;
 
 
        case E_SCORE_MACH_SCORE3:
        case E_SCORE_MACH_SCORE3:
          e_set = bfd_mach_score3;
          e_set = bfd_mach_score3;
          break;
          break;
        }
        }
    }
    }
 
 
  return bfd_default_set_arch_mach (abfd, bfd_arch_score, e_set);
  return bfd_default_set_arch_mach (abfd, bfd_arch_score, e_set);
}
}
 
 
bfd_boolean
bfd_boolean
_bfd_score_elf_common_definition (Elf_Internal_Sym *sym)
_bfd_score_elf_common_definition (Elf_Internal_Sym *sym)
{
{
  return (sym->st_shndx == SHN_COMMON || sym->st_shndx == SHN_SCORE_SCOMMON);
  return (sym->st_shndx == SHN_COMMON || sym->st_shndx == SHN_SCORE_SCOMMON);
}
}
 
 
/*****************************************************************************/
/*****************************************************************************/
 
 
 
 
#define USE_REL                         1
#define USE_REL                         1
#define TARGET_LITTLE_SYM               bfd_elf32_littlescore_vec
#define TARGET_LITTLE_SYM               bfd_elf32_littlescore_vec
#define TARGET_LITTLE_NAME              "elf32-littlescore"
#define TARGET_LITTLE_NAME              "elf32-littlescore"
#define TARGET_BIG_SYM                  bfd_elf32_bigscore_vec
#define TARGET_BIG_SYM                  bfd_elf32_bigscore_vec
#define TARGET_BIG_NAME                 "elf32-bigscore"
#define TARGET_BIG_NAME                 "elf32-bigscore"
#define ELF_ARCH                        bfd_arch_score
#define ELF_ARCH                        bfd_arch_score
#define ELF_MACHINE_CODE                EM_SCORE
#define ELF_MACHINE_CODE                EM_SCORE
#define ELF_MACHINE_ALT1                EM_SCORE_OLD
#define ELF_MACHINE_ALT1                EM_SCORE_OLD
#define ELF_MAXPAGESIZE                 0x8000
#define ELF_MAXPAGESIZE                 0x8000
 
 
#define elf_info_to_howto               0
#define elf_info_to_howto               0
#define elf_info_to_howto_rel           _bfd_score_info_to_howto
#define elf_info_to_howto_rel           _bfd_score_info_to_howto
#define elf_backend_relocate_section    _bfd_score_elf_relocate_section
#define elf_backend_relocate_section    _bfd_score_elf_relocate_section
#define elf_backend_check_relocs        _bfd_score_elf_check_relocs
#define elf_backend_check_relocs        _bfd_score_elf_check_relocs
#define elf_backend_add_symbol_hook     _bfd_score_elf_add_symbol_hook
#define elf_backend_add_symbol_hook     _bfd_score_elf_add_symbol_hook
#define elf_backend_symbol_processing   _bfd_score_elf_symbol_processing
#define elf_backend_symbol_processing   _bfd_score_elf_symbol_processing
#define elf_backend_link_output_symbol_hook \
#define elf_backend_link_output_symbol_hook \
  _bfd_score_elf_link_output_symbol_hook
  _bfd_score_elf_link_output_symbol_hook
#define elf_backend_section_from_bfd_section \
#define elf_backend_section_from_bfd_section \
  _bfd_score_elf_section_from_bfd_section
  _bfd_score_elf_section_from_bfd_section
#define elf_backend_adjust_dynamic_symbol \
#define elf_backend_adjust_dynamic_symbol \
  _bfd_score_elf_adjust_dynamic_symbol
  _bfd_score_elf_adjust_dynamic_symbol
#define elf_backend_always_size_sections \
#define elf_backend_always_size_sections \
  _bfd_score_elf_always_size_sections
  _bfd_score_elf_always_size_sections
#define elf_backend_size_dynamic_sections \
#define elf_backend_size_dynamic_sections \
  _bfd_score_elf_size_dynamic_sections
  _bfd_score_elf_size_dynamic_sections
#define elf_backend_omit_section_dynsym \
#define elf_backend_omit_section_dynsym \
  ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true)
  ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true)
#define elf_backend_create_dynamic_sections \
#define elf_backend_create_dynamic_sections \
  _bfd_score_elf_create_dynamic_sections
  _bfd_score_elf_create_dynamic_sections
#define elf_backend_finish_dynamic_symbol \
#define elf_backend_finish_dynamic_symbol \
  _bfd_score_elf_finish_dynamic_symbol
  _bfd_score_elf_finish_dynamic_symbol
#define elf_backend_finish_dynamic_sections \
#define elf_backend_finish_dynamic_sections \
  _bfd_score_elf_finish_dynamic_sections
  _bfd_score_elf_finish_dynamic_sections
#define elf_backend_fake_sections         _bfd_score_elf_fake_sections
#define elf_backend_fake_sections         _bfd_score_elf_fake_sections
#define elf_backend_section_processing    _bfd_score_elf_section_processing
#define elf_backend_section_processing    _bfd_score_elf_section_processing
#define elf_backend_write_section         _bfd_score_elf_write_section
#define elf_backend_write_section         _bfd_score_elf_write_section
#define elf_backend_copy_indirect_symbol  _bfd_score_elf_copy_indirect_symbol
#define elf_backend_copy_indirect_symbol  _bfd_score_elf_copy_indirect_symbol
#define elf_backend_hide_symbol           _bfd_score_elf_hide_symbol
#define elf_backend_hide_symbol           _bfd_score_elf_hide_symbol
#define elf_backend_discard_info          _bfd_score_elf_discard_info
#define elf_backend_discard_info          _bfd_score_elf_discard_info
#define elf_backend_ignore_discarded_relocs \
#define elf_backend_ignore_discarded_relocs \
  _bfd_score_elf_ignore_discarded_relocs
  _bfd_score_elf_ignore_discarded_relocs
#define elf_backend_gc_mark_hook          _bfd_score_elf_gc_mark_hook
#define elf_backend_gc_mark_hook          _bfd_score_elf_gc_mark_hook
#define elf_backend_grok_prstatus         _bfd_score_elf_grok_prstatus
#define elf_backend_grok_prstatus         _bfd_score_elf_grok_prstatus
#define elf_backend_grok_psinfo           _bfd_score_elf_grok_psinfo
#define elf_backend_grok_psinfo           _bfd_score_elf_grok_psinfo
#define elf_backend_can_gc_sections       1
#define elf_backend_can_gc_sections       1
#define elf_backend_want_plt_sym          0
#define elf_backend_want_plt_sym          0
#define elf_backend_got_header_size       (4 * SCORE_RESERVED_GOTNO)
#define elf_backend_got_header_size       (4 * SCORE_RESERVED_GOTNO)
#define elf_backend_plt_header_size       0
#define elf_backend_plt_header_size       0
#define elf_backend_collect               TRUE
#define elf_backend_collect               TRUE
#define elf_backend_type_change_ok        TRUE
#define elf_backend_type_change_ok        TRUE
#define elf_backend_object_p                  _bfd_score_elf_score_object_p
#define elf_backend_object_p                  _bfd_score_elf_score_object_p
 
 
#define bfd_elf32_bfd_reloc_type_lookup      elf32_score_reloc_type_lookup
#define bfd_elf32_bfd_reloc_type_lookup      elf32_score_reloc_type_lookup
#define bfd_elf32_bfd_reloc_name_lookup \
#define bfd_elf32_bfd_reloc_name_lookup \
  elf32_score_reloc_name_lookup
  elf32_score_reloc_name_lookup
#define bfd_elf32_bfd_link_hash_table_create elf32_score_link_hash_table_create
#define bfd_elf32_bfd_link_hash_table_create elf32_score_link_hash_table_create
#define bfd_elf32_bfd_print_private_bfd_data elf32_score_print_private_bfd_data
#define bfd_elf32_bfd_print_private_bfd_data elf32_score_print_private_bfd_data
#define bfd_elf32_bfd_merge_private_bfd_data elf32_score_merge_private_bfd_data
#define bfd_elf32_bfd_merge_private_bfd_data elf32_score_merge_private_bfd_data
#define bfd_elf32_new_section_hook           elf32_score_new_section_hook
#define bfd_elf32_new_section_hook           elf32_score_new_section_hook
 
 
#include "elf32-target.h"
#include "elf32-target.h"
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.