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

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [gnu-src/] [gdb-6.8/] [bfd/] [elfxx-mips.c] - Diff between revs 157 and 225

Go to most recent revision | Show entire file | Details | Blame | View Log

Rev 157 Rev 225
Line 1... Line 1...
/* MIPS-specific support for ELF
/* MIPS-specific support for ELF
   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
   2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
   2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
 
 
   Most of the information added by Ian Lance Taylor, Cygnus Support,
   Most of the information added by Ian Lance Taylor, Cygnus Support,
   <ian@cygnus.com>.
   <ian@cygnus.com>.
   N32/64 ABI support added by Mark Mitchell, CodeSourcery, LLC.
   N32/64 ABI support added by Mark Mitchell, CodeSourcery, LLC.
   <mark@codesourcery.com>
   <mark@codesourcery.com>
Line 143... Line 143...
  /* 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 global .got entries that are in the GGA_RELOC_ONLY area.  */
 
  unsigned int reloc_only_gotno;
  /* The number of .got slots used for TLS.  */
  /* The number of .got slots used for TLS.  */
  unsigned int tls_gotno;
  unsigned int tls_gotno;
  /* The first unused TLS .got entry.  Used only during
  /* The first unused TLS .got entry.  Used only during
     mips_elf_initialize_tls_index.  */
     mips_elf_initialize_tls_index.  */
  unsigned int tls_assigned_gotno;
  unsigned int tls_assigned_gotno;
Line 232... Line 234...
struct _mips_elf_section_data
struct _mips_elf_section_data
{
{
  struct bfd_elf_section_data elf;
  struct bfd_elf_section_data elf;
  union
  union
  {
  {
    struct mips_got_info *got_info;
 
    bfd_byte *tdata;
    bfd_byte *tdata;
  } u;
  } u;
};
};
 
 
#define mips_elf_section_data(sec) \
#define mips_elf_section_data(sec) \
  ((struct _mips_elf_section_data *) elf_section_data (sec))
  ((struct _mips_elf_section_data *) elf_section_data (sec))
 
 
 
#define is_mips_elf(bfd)                                \
 
  (bfd_get_flavour (bfd) == bfd_target_elf_flavour      \
 
   && elf_tdata (bfd) != NULL                           \
 
   && elf_object_id (bfd) == MIPS_ELF_TDATA)
 
 
 
/* The ABI says that every symbol used by dynamic relocations must have
 
   a global GOT entry.  Among other things, this provides the dynamic
 
   linker with a free, directly-indexed cache.  The GOT can therefore
 
   contain symbols that are not referenced by GOT relocations themselves
 
   (in other words, it may have symbols that are not referenced by things
 
   like R_MIPS_GOT16 and R_MIPS_GOT_PAGE).
 
 
 
   GOT relocations are less likely to overflow if we put the associated
 
   GOT entries towards the beginning.  We therefore divide the global
 
   GOT entries into two areas: "normal" and "reloc-only".  Entries in
 
   the first area can be used for both dynamic relocations and GP-relative
 
   accesses, while those in the "reloc-only" area are for dynamic
 
   relocations only.
 
 
 
   These GGA_* ("Global GOT Area") values are organised so that lower
 
   values are more general than higher values.  Also, non-GGA_NONE
 
   values are ordered by the position of the area in the GOT.  */
 
#define GGA_NORMAL 0
 
#define GGA_RELOC_ONLY 1
 
#define GGA_NONE 2
 
 
 
/* Information about a non-PIC interface to a PIC function.  There are
 
   two ways of creating these interfaces.  The first is to add:
 
 
 
        lui     $25,%hi(func)
 
        addiu   $25,$25,%lo(func)
 
 
 
   immediately before a PIC function "func".  The second is to add:
 
 
 
        lui     $25,%hi(func)
 
        j       func
 
        addiu   $25,$25,%lo(func)
 
 
 
   to a separate trampoline section.
 
 
 
   Stubs of the first kind go in a new section immediately before the
 
   target function.  Stubs of the second kind go in a single section
 
   pointed to by the hash table's "strampoline" field.  */
 
struct mips_elf_la25_stub {
 
  /* The generated section that contains this stub.  */
 
  asection *stub_section;
 
 
 
  /* The offset of the stub from the start of STUB_SECTION.  */
 
  bfd_vma offset;
 
 
 
  /* One symbol for the original function.  Its location is available
 
     in H->root.root.u.def.  */
 
  struct mips_elf_link_hash_entry *h;
 
};
 
 
 
/* Macros for populating a mips_elf_la25_stub.  */
 
 
 
#define LA25_LUI(VAL) (0x3c190000 | (VAL))      /* lui t9,VAL */
 
#define LA25_J(VAL) (0x08000000 | (((VAL) >> 2) & 0x3ffffff)) /* j VAL */
 
#define LA25_ADDIU(VAL) (0x27390000 | (VAL))    /* addiu t9,t9,VAL */
 
 
/* This structure is passed to mips_elf_sort_hash_table_f when sorting
/* This structure is passed to mips_elf_sort_hash_table_f when sorting
   the dynamic symbols.  */
   the dynamic symbols.  */
 
 
struct mips_elf_hash_sort_data
struct mips_elf_hash_sort_data
{
{
Line 270... Line 332...
  struct elf_link_hash_entry root;
  struct elf_link_hash_entry root;
 
 
  /* External symbol information.  */
  /* External symbol information.  */
  EXTR esym;
  EXTR esym;
 
 
 
  /* The la25 stub we have created for ths symbol, if any.  */
 
  struct mips_elf_la25_stub *la25_stub;
 
 
  /* Number of R_MIPS_32, R_MIPS_REL32, or R_MIPS_64 relocs against
  /* Number of R_MIPS_32, R_MIPS_REL32, or R_MIPS_64 relocs against
     this symbol.  */
     this symbol.  */
  unsigned int possibly_dynamic_relocs;
  unsigned int possibly_dynamic_relocs;
 
 
  /* If the R_MIPS_32, R_MIPS_REL32, or R_MIPS_64 reloc is against
 
     a readonly section.  */
 
  bfd_boolean readonly_reloc;
 
 
 
  /* We must not create a stub for a symbol that has relocations
 
     related to taking the function's address, i.e. any but
 
     R_MIPS_CALL*16 ones -- see "MIPS ABI Supplement, 3rd Edition",
 
     p. 4-20.  */
 
  bfd_boolean no_fn_stub;
 
 
 
  /* If there is a stub that 32 bit functions should use to call this
  /* If there is a stub that 32 bit functions should use to call this
     16 bit function, this points to the section containing the stub.  */
     16 bit function, this points to the section containing the stub.  */
  asection *fn_stub;
  asection *fn_stub;
 
 
  /* Whether we need the fn_stub; this is set if this symbol appears
 
     in any relocs other than a 16 bit call.  */
 
  bfd_boolean need_fn_stub;
 
 
 
  /* If there is a stub that 16 bit functions should use to call this
  /* If there is a stub that 16 bit functions should use to call this
     32 bit function, this points to the section containing the stub.  */
     32 bit function, this points to the section containing the stub.  */
  asection *call_stub;
  asection *call_stub;
 
 
  /* This is like the call_stub field, but it is used if the function
  /* This is like the call_stub field, but it is used if the function
     being called returns a floating point value.  */
     being called returns a floating point value.  */
  asection *call_fp_stub;
  asection *call_fp_stub;
 
 
  /* Are we forced local?  This will only be set if we have converted
 
     the initial global GOT entry to a local GOT entry.  */
 
  bfd_boolean forced_local;
 
 
 
  /* Are we referenced by some kind of relocation?  */
 
  bfd_boolean is_relocation_target;
 
 
 
  /* Are we referenced by branch relocations?  */
 
  bfd_boolean is_branch_target;
 
 
 
#define GOT_NORMAL      0
#define GOT_NORMAL      0
#define GOT_TLS_GD      1
#define GOT_TLS_GD      1
#define GOT_TLS_LDM     2
#define GOT_TLS_LDM     2
#define GOT_TLS_IE      4
#define GOT_TLS_IE      4
#define GOT_TLS_OFFSET_DONE    0x40
#define GOT_TLS_OFFSET_DONE    0x40
#define GOT_TLS_DONE    0x80
#define GOT_TLS_DONE    0x80
  unsigned char tls_type;
  unsigned char tls_type;
 
 
  /* This is only used in single-GOT mode; in multi-GOT mode there
  /* This is only used in single-GOT mode; in multi-GOT mode there
     is one mips_got_entry per GOT entry, so the offset is stored
     is one mips_got_entry per GOT entry, so the offset is stored
     there.  In single-GOT mode there may be many mips_got_entry
     there.  In single-GOT mode there may be many mips_got_entry
     structures all referring to the same GOT slot.  It might be
     structures all referring to the same GOT slot.  It might be
     possible to use root.got.offset instead, but that field is
     possible to use root.got.offset instead, but that field is
     overloaded already.  */
     overloaded already.  */
  bfd_vma tls_got_offset;
  bfd_vma tls_got_offset;
 
 
 
  /* The highest GGA_* value that satisfies all references to this symbol.  */
 
  unsigned int global_got_area : 2;
 
 
 
  /* True if one of the relocations described by possibly_dynamic_relocs
 
     is against a readonly section.  */
 
  unsigned int readonly_reloc : 1;
 
 
 
  /* True if there is a relocation against this symbol that must be
 
     resolved by the static linker (in other words, if the relocation
 
     cannot possibly be made dynamic).  */
 
  unsigned int has_static_relocs : 1;
 
 
 
  /* True if we must not create a .MIPS.stubs entry for this symbol.
 
     This is set, for example, if there are relocations related to
 
     taking the function's address, i.e. any but R_MIPS_CALL*16 ones.
 
     See "MIPS ABI Supplement, 3rd Edition", p. 4-20.  */
 
  unsigned int no_fn_stub : 1;
 
 
 
  /* Whether we need the fn_stub; this is true if this symbol appears
 
     in any relocs other than a 16 bit call.  */
 
  unsigned int need_fn_stub : 1;
 
 
 
  /* True if this symbol is referenced by branch relocations from
 
     any non-PIC input file.  This is used to determine whether an
 
     la25 stub is required.  */
 
  unsigned int has_nonpic_branches : 1;
 
 
 
  /* Does this symbol need a traditional MIPS lazy-binding stub
 
     (as opposed to a PLT entry)?  */
 
  unsigned int needs_lazy_stub : 1;
};
};
 
 
/* MIPS ELF linker hash table.  */
/* MIPS ELF linker hash table.  */
 
 
struct mips_elf_link_hash_table
struct mips_elf_link_hash_table
Line 336... Line 409...
#if 0
#if 0
  /* We no longer use this.  */
  /* We no longer use this.  */
  /* String section indices for the dynamic section symbols.  */
  /* String section indices for the dynamic section symbols.  */
  bfd_size_type dynsym_sec_strindex[SIZEOF_MIPS_DYNSYM_SECNAMES];
  bfd_size_type dynsym_sec_strindex[SIZEOF_MIPS_DYNSYM_SECNAMES];
#endif
#endif
 
 
  /* The number of .rtproc entries.  */
  /* The number of .rtproc entries.  */
  bfd_size_type procedure_count;
  bfd_size_type procedure_count;
 
 
  /* The size of the .compact_rel section (if SGI_COMPAT).  */
  /* The size of the .compact_rel section (if SGI_COMPAT).  */
  bfd_size_type compact_rel_size;
  bfd_size_type compact_rel_size;
 
 
  /* This flag indicates that the value of DT_MIPS_RLD_MAP dynamic
  /* This flag indicates that the value of DT_MIPS_RLD_MAP dynamic
     entry is set to the address of __rld_obj_head as in IRIX5.  */
     entry is set to the address of __rld_obj_head as in IRIX5.  */
  bfd_boolean use_rld_obj_head;
  bfd_boolean use_rld_obj_head;
 
 
  /* This is the value of the __rld_map or __rld_obj_head symbol.  */
  /* This is the value of the __rld_map or __rld_obj_head symbol.  */
  bfd_vma rld_value;
  bfd_vma rld_value;
 
 
  /* This is set if we see any mips16 stub sections.  */
  /* This is set if we see any mips16 stub sections.  */
  bfd_boolean mips16_stubs_seen;
  bfd_boolean mips16_stubs_seen;
  /* True if we've computed the size of the GOT.  */
 
  bfd_boolean computed_got_sizes;
  /* True if we can generate copy relocs and PLTs.  */
 
  bfd_boolean use_plts_and_copy_relocs;
 
 
  /* True if we're generating code for VxWorks.  */
  /* True if we're generating code for VxWorks.  */
  bfd_boolean is_vxworks;
  bfd_boolean is_vxworks;
 
 
  /* True if we already reported the small-data section overflow.  */
  /* True if we already reported the small-data section overflow.  */
  bfd_boolean small_data_overflow_reported;
  bfd_boolean small_data_overflow_reported;
 
 
  /* Shortcuts to some dynamic sections, or NULL if they are not
  /* Shortcuts to some dynamic sections, or NULL if they are not
     being used.  */
     being used.  */
  asection *srelbss;
  asection *srelbss;
  asection *sdynbss;
  asection *sdynbss;
  asection *srelplt;
  asection *srelplt;
  asection *srelplt2;
  asection *srelplt2;
  asection *sgotplt;
  asection *sgotplt;
  asection *splt;
  asection *splt;
  /* The size of the PLT header in bytes (VxWorks only).  */
  asection *sstubs;
 
  asection *sgot;
 
 
 
  /* The master GOT information.  */
 
  struct mips_got_info *got_info;
 
 
 
  /* The size of the PLT header in bytes.  */
  bfd_vma plt_header_size;
  bfd_vma plt_header_size;
  /* The size of a PLT entry in bytes (VxWorks only).  */
 
 
  /* The size of a PLT entry in bytes.  */
  bfd_vma plt_entry_size;
  bfd_vma plt_entry_size;
 
 
 
  /* The number of functions that need a lazy-binding stub.  */
 
  bfd_vma lazy_stub_count;
 
 
  /* The size of a function stub entry in bytes.  */
  /* The size of a function stub entry in bytes.  */
  bfd_vma function_stub_size;
  bfd_vma function_stub_size;
 
 
 
  /* The number of reserved entries at the beginning of the GOT.  */
 
  unsigned int reserved_gotno;
 
 
 
  /* The section used for mips_elf_la25_stub trampolines.
 
     See the comment above that structure for details.  */
 
  asection *strampoline;
 
 
 
  /* A table of mips_elf_la25_stubs, indexed by (input_section, offset)
 
     pairs.  */
 
  htab_t la25_stubs;
 
 
 
  /* A function FN (NAME, IS, OS) that creates a new input section
 
     called NAME and links it to output section OS.  If IS is nonnull,
 
     the new section should go immediately before it, otherwise it
 
     should go at the (current) beginning of OS.
 
 
 
     The function returns the new section on success, otherwise it
 
     returns null.  */
 
  asection *(*add_stub_section) (const char *, asection *, asection *);
 
};
 
 
 
/* A structure used to communicate with htab_traverse callbacks.  */
 
struct mips_htab_traverse_info {
 
  /* The usual link-wide information.  */
 
  struct bfd_link_info *info;
 
  bfd *output_bfd;
 
 
 
  /* Starts off FALSE and is set to TRUE if the link should be aborted.  */
 
  bfd_boolean error;
};
};
 
 
#define TLS_RELOC_P(r_type) \
#define TLS_RELOC_P(r_type) \
  (r_type == R_MIPS_TLS_DTPMOD32                \
  (r_type == R_MIPS_TLS_DTPMOD32                \
   || r_type == R_MIPS_TLS_DTPMOD64             \
   || r_type == R_MIPS_TLS_DTPMOD64             \
Line 517... Line 640...
} RPDR, *pRPDR;
} RPDR, *pRPDR;
#define cbRPDR sizeof (RPDR)
#define cbRPDR sizeof (RPDR)
#define rpdNil ((pRPDR) 0)
#define rpdNil ((pRPDR) 0)


static struct mips_got_entry *mips_elf_create_local_got_entry
static struct mips_got_entry *mips_elf_create_local_got_entry
  (bfd *, struct bfd_link_info *, bfd *, struct mips_got_info *, asection *,
  (bfd *, struct bfd_link_info *, bfd *, bfd_vma, unsigned long,
   bfd_vma, unsigned long, struct mips_elf_link_hash_entry *, int);
   struct mips_elf_link_hash_entry *, int);
static bfd_boolean mips_elf_sort_hash_table_f
static bfd_boolean mips_elf_sort_hash_table_f
  (struct mips_elf_link_hash_entry *, void *);
  (struct mips_elf_link_hash_entry *, void *);
static bfd_vma mips_elf_high
static bfd_vma mips_elf_high
  (bfd_vma);
  (bfd_vma);
static bfd_boolean mips16_stub_section_p
 
  (bfd *, asection *);
 
static bfd_boolean mips_elf_create_dynamic_relocation
static bfd_boolean mips_elf_create_dynamic_relocation
  (bfd *, struct bfd_link_info *, const Elf_Internal_Rela *,
  (bfd *, struct bfd_link_info *, const Elf_Internal_Rela *,
   struct mips_elf_link_hash_entry *, asection *, bfd_vma,
   struct mips_elf_link_hash_entry *, asection *, bfd_vma,
   bfd_vma *, asection *);
   bfd_vma *, asection *);
static hashval_t mips_elf_got_entry_hash
static hashval_t mips_elf_got_entry_hash
Line 539... Line 660...
  (struct mips_got_info *, bfd *);
  (struct mips_got_info *, bfd *);
 
 
/* 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;
 
 
 
/* True if ABFD is for CPUs with load interlocking that include
 
   non-MIPS1 CPUs and R3900.  */
 
#define LOAD_INTERLOCKS_P(abfd) \
 
  (   ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) != E_MIPS_ARCH_1) \
 
   || ((elf_elfheader (abfd)->e_flags & EF_MIPS_MACH) == E_MIPS_MACH_3900))
 
 
 
/* True if ABFD is for CPUs that are faster if JAL is converted to BAL.
 
   This should be safe for all architectures.  We enable this predicate
 
   for RM9000 for now.  */
 
#define JAL_TO_BAL_P(abfd) \
 
  ((elf_elfheader (abfd)->e_flags & EF_MIPS_MACH) == E_MIPS_MACH_9000)
 
 
 
/* True if ABFD is for CPUs that are faster if JALR is converted to BAL.
 
   This should be safe for all architectures.  We enable this predicate for
 
   all CPUs.  */
 
#define JALR_TO_BAL_P(abfd) 1
 
 
 
/* True if ABFD is a PIC object.  */
 
#define PIC_OBJECT_P(abfd) \
 
  ((elf_elfheader (abfd)->e_flags & EF_MIPS_PIC) != 0)
 
 
/* Nonzero if ABFD is using the N32 ABI.  */
/* Nonzero if ABFD is using the N32 ABI.  */
#define ABI_N32_P(abfd) \
#define ABI_N32_P(abfd) \
  ((elf_elfheader (abfd)->e_flags & EF_MIPS_ABI2) != 0)
  ((elf_elfheader (abfd)->e_flags & EF_MIPS_ABI2) != 0)
 
 
/* Nonzero if ABFD is using the N64 ABI.  */
/* Nonzero if ABFD is using the N64 ABI.  */
Line 609... Line 751...
#define MIPS_ELF_PUT_WORD(abfd, val, ptr)       \
#define MIPS_ELF_PUT_WORD(abfd, val, ptr)       \
  (ABI_64_P (abfd)                              \
  (ABI_64_P (abfd)                              \
   ? bfd_put_64 (abfd, val, ptr)                \
   ? bfd_put_64 (abfd, val, ptr)                \
   : bfd_put_32 (abfd, val, ptr))
   : bfd_put_32 (abfd, val, ptr))
 
 
 
/* The opcode for word-sized loads (LW or LD).  */
 
#define MIPS_ELF_LOAD_WORD(abfd) \
 
  (ABI_64_P (abfd) ? 0xdc000000 : 0x8c000000)
 
 
/* Add a dynamic symbol table-entry.  */
/* Add a dynamic symbol table-entry.  */
#define MIPS_ELF_ADD_DYNAMIC_ENTRY(info, tag, val)      \
#define MIPS_ELF_ADD_DYNAMIC_ENTRY(info, tag, val)      \
  _bfd_elf_add_dynamic_entry (info, tag, val)
  _bfd_elf_add_dynamic_entry (info, tag, val)
 
 
#define MIPS_ELF_RTYPE_TO_HOWTO(abfd, rtype, rela)                      \
#define MIPS_ELF_RTYPE_TO_HOWTO(abfd, rtype, rela)                      \
Line 642... Line 788...
/* 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)
 
 
/* The number of local .got entries we reserve.  */
/* The value to write into got[1] for SVR4 targets, to identify it is
#define MIPS_RESERVED_GOTNO(INFO) \
   a GNU object.  The dynamic linker can then use got[1] to store the
  (mips_elf_hash_table (INFO)->is_vxworks ? 3 : 2)
   module pointer.  */
 
#define MIPS_ELF_GNU_GOT1_MASK(abfd) \
 
  ((bfd_vma) 1 << (ABI_64_P (abfd) ? 63 : 31))
 
 
/* The offset of $gp from the beginning of the .got section.  */
/* The offset of $gp from the beginning of the .got section.  */
#define ELF_MIPS_GP_OFFSET(INFO) \
#define ELF_MIPS_GP_OFFSET(INFO) \
  (mips_elf_hash_table (INFO)->is_vxworks ? 0x0 : 0x7ff0)
  (mips_elf_hash_table (INFO)->is_vxworks ? 0x0 : 0x7ff0)
 
 
Line 744... Line 892...
 
 
#define FN_STUB_P(name) CONST_STRNEQ (name, FN_STUB)
#define FN_STUB_P(name) CONST_STRNEQ (name, FN_STUB)
#define CALL_STUB_P(name) CONST_STRNEQ (name, CALL_STUB)
#define CALL_STUB_P(name) CONST_STRNEQ (name, CALL_STUB)
#define CALL_FP_STUB_P(name) CONST_STRNEQ (name, CALL_FP_STUB)
#define CALL_FP_STUB_P(name) CONST_STRNEQ (name, CALL_FP_STUB)


 
/* The format of the first PLT entry in an O32 executable.  */
 
static const bfd_vma mips_o32_exec_plt0_entry[] =
 
{
 
  0x3c1c0000,   /* lui $28, %hi(&GOTPLT[0])                             */
 
  0x8f990000,   /* lw $25, %lo(&GOTPLT[0])($28)                         */
 
  0x279c0000,   /* addiu $28, $28, %lo(&GOTPLT[0])                      */
 
  0x031cc023,   /* subu $24, $24, $28                                   */
 
  0x03e07821,   /* move $15, $31                                        */
 
  0x0018c082,   /* srl $24, $24, 2                                      */
 
  0x0320f809,   /* jalr $25                                             */
 
  0x2718fffe    /* subu $24, $24, 2                                     */
 
};
 
 
 
/* The format of the first PLT entry in an N32 executable.  Different
 
   because gp ($28) is not available; we use t2 ($14) instead.  */
 
static const bfd_vma mips_n32_exec_plt0_entry[] =
 
{
 
  0x3c0e0000,   /* lui $14, %hi(&GOTPLT[0])                             */
 
  0x8dd90000,   /* lw $25, %lo(&GOTPLT[0])($14)                         */
 
  0x25ce0000,   /* addiu $14, $14, %lo(&GOTPLT[0])                      */
 
  0x030ec023,   /* subu $24, $24, $14                                   */
 
  0x03e07821,   /* move $15, $31                                        */
 
  0x0018c082,   /* srl $24, $24, 2                                      */
 
  0x0320f809,   /* jalr $25                                             */
 
  0x2718fffe    /* subu $24, $24, 2                                     */
 
};
 
 
 
/* The format of the first PLT entry in an N64 executable.  Different
 
   from N32 because of the increased size of GOT entries.  */
 
static const bfd_vma mips_n64_exec_plt0_entry[] =
 
{
 
  0x3c0e0000,   /* lui $14, %hi(&GOTPLT[0])                             */
 
  0xddd90000,   /* ld $25, %lo(&GOTPLT[0])($14)                         */
 
  0x25ce0000,   /* addiu $14, $14, %lo(&GOTPLT[0])                      */
 
  0x030ec023,   /* subu $24, $24, $14                                   */
 
  0x03e07821,   /* move $15, $31                                        */
 
  0x0018c0c2,   /* srl $24, $24, 3                                      */
 
  0x0320f809,   /* jalr $25                                             */
 
  0x2718fffe    /* subu $24, $24, 2                                     */
 
};
 
 
 
/* The format of subsequent PLT entries.  */
 
static const bfd_vma mips_exec_plt_entry[] =
 
{
 
  0x3c0f0000,   /* lui $15, %hi(.got.plt entry)                 */
 
  0x01f90000,   /* l[wd] $25, %lo(.got.plt entry)($15)          */
 
  0x25f80000,   /* addiu $24, $15, %lo(.got.plt entry)          */
 
  0x03200008    /* jr $25                                       */
 
};
 
 
/* The format of the first PLT entry in a VxWorks executable.  */
/* The format of the first PLT entry in a VxWorks executable.  */
static const bfd_vma mips_vxworks_exec_plt0_entry[] = {
static const bfd_vma mips_vxworks_exec_plt0_entry[] =
 
{
  0x3c190000,   /* lui t9, %hi(_GLOBAL_OFFSET_TABLE_)           */
  0x3c190000,   /* lui t9, %hi(_GLOBAL_OFFSET_TABLE_)           */
  0x27390000,   /* addiu t9, t9, %lo(_GLOBAL_OFFSET_TABLE_)     */
  0x27390000,   /* addiu t9, t9, %lo(_GLOBAL_OFFSET_TABLE_)     */
  0x8f390008,   /* lw t9, 8(t9)                                 */
  0x8f390008,   /* lw t9, 8(t9)                                 */
  0x00000000,   /* nop                                          */
  0x00000000,   /* nop                                          */
  0x03200008,   /* jr t9                                        */
  0x03200008,   /* jr t9                                        */
  0x00000000    /* nop                                          */
  0x00000000    /* nop                                          */
};
};
 
 
/* The format of subsequent PLT entries.  */
/* The format of subsequent PLT entries.  */
static const bfd_vma mips_vxworks_exec_plt_entry[] = {
static const bfd_vma mips_vxworks_exec_plt_entry[] =
 
{
  0x10000000,   /* b .PLT_resolver                      */
  0x10000000,   /* b .PLT_resolver                      */
  0x24180000,   /* li t8, <pltindex>                    */
  0x24180000,   /* li t8, <pltindex>                    */
  0x3c190000,   /* lui t9, %hi(<.got.plt slot>)         */
  0x3c190000,   /* lui t9, %hi(<.got.plt slot>)         */
  0x27390000,   /* addiu t9, t9, %lo(<.got.plt slot>)   */
  0x27390000,   /* addiu t9, t9, %lo(<.got.plt slot>)   */
  0x8f390000,   /* lw t9, 0(t9)                         */
  0x8f390000,   /* lw t9, 0(t9)                         */
Line 767... Line 967...
  0x03200008,   /* jr t9                                */
  0x03200008,   /* jr t9                                */
  0x00000000    /* nop                                  */
  0x00000000    /* nop                                  */
};
};
 
 
/* The format of the first PLT entry in a VxWorks shared object.  */
/* The format of the first PLT entry in a VxWorks shared object.  */
static const bfd_vma mips_vxworks_shared_plt0_entry[] = {
static const bfd_vma mips_vxworks_shared_plt0_entry[] =
 
{
  0x8f990008,   /* lw t9, 8(gp)         */
  0x8f990008,   /* lw t9, 8(gp)         */
  0x00000000,   /* nop                  */
  0x00000000,   /* nop                  */
  0x03200008,   /* jr t9                */
  0x03200008,   /* jr t9                */
  0x00000000,   /* nop                  */
  0x00000000,   /* nop                  */
  0x00000000,   /* nop                  */
  0x00000000,   /* nop                  */
  0x00000000    /* nop                  */
  0x00000000    /* nop                  */
};
};
 
 
/* The format of subsequent PLT entries.  */
/* The format of subsequent PLT entries.  */
static const bfd_vma mips_vxworks_shared_plt_entry[] = {
static const bfd_vma mips_vxworks_shared_plt_entry[] =
 
{
  0x10000000,   /* b .PLT_resolver      */
  0x10000000,   /* b .PLT_resolver      */
  0x24180000    /* li t8, <pltindex>    */
  0x24180000    /* li t8, <pltindex>    */
};
};


/* Look up an entry in a MIPS ELF linker hash table.  */
/* Look up an entry in a MIPS ELF linker hash table.  */
Line 853... Line 1055...
      /* Set local fields.  */
      /* Set local fields.  */
      memset (&ret->esym, 0, sizeof (EXTR));
      memset (&ret->esym, 0, sizeof (EXTR));
      /* We use -2 as a marker to indicate that the information has
      /* We use -2 as a marker to indicate that the information has
         not been set.  -1 means there is no associated ifd.  */
         not been set.  -1 means there is no associated ifd.  */
      ret->esym.ifd = -2;
      ret->esym.ifd = -2;
 
      ret->la25_stub = 0;
      ret->possibly_dynamic_relocs = 0;
      ret->possibly_dynamic_relocs = 0;
      ret->readonly_reloc = FALSE;
 
      ret->no_fn_stub = FALSE;
 
      ret->fn_stub = NULL;
      ret->fn_stub = NULL;
      ret->need_fn_stub = FALSE;
 
      ret->call_stub = NULL;
      ret->call_stub = NULL;
      ret->call_fp_stub = NULL;
      ret->call_fp_stub = NULL;
      ret->forced_local = FALSE;
 
      ret->is_branch_target = FALSE;
 
      ret->is_relocation_target = FALSE;
 
      ret->tls_type = GOT_NORMAL;
      ret->tls_type = GOT_NORMAL;
 
      ret->global_got_area = GGA_NONE;
 
      ret->readonly_reloc = FALSE;
 
      ret->has_static_relocs = FALSE;
 
      ret->no_fn_stub = FALSE;
 
      ret->need_fn_stub = FALSE;
 
      ret->has_nonpic_branches = FALSE;
 
      ret->needs_lazy_stub = FALSE;
    }
    }
 
 
  return (struct bfd_hash_entry *) ret;
  return (struct bfd_hash_entry *) ret;
}
}
 
 
Line 1140... Line 1344...
    free (ss);
    free (ss);
  if (sv != NULL)
  if (sv != NULL)
    free (sv);
    free (sv);
  return FALSE;
  return FALSE;
}
}
 

 
/* We're going to create a stub for H.  Create a symbol for the stub's
 
   value and size, to help make the disassembly easier to read.  */
 
 
 
static bfd_boolean
 
mips_elf_create_stub_symbol (struct bfd_link_info *info,
 
                             struct mips_elf_link_hash_entry *h,
 
                             const char *prefix, asection *s, bfd_vma value,
 
                             bfd_vma size)
 
{
 
  struct bfd_link_hash_entry *bh;
 
  struct elf_link_hash_entry *elfh;
 
  const char *name;
 
 
 
  /* Create a new symbol.  */
 
  name = ACONCAT ((prefix, h->root.root.root.string, NULL));
 
  bh = NULL;
 
  if (!_bfd_generic_link_add_one_symbol (info, s->owner, name,
 
                                         BSF_LOCAL, s, value, NULL,
 
                                         TRUE, FALSE, &bh))
 
    return FALSE;
 
 
 
  /* Make it a local function.  */
 
  elfh = (struct elf_link_hash_entry *) bh;
 
  elfh->type = ELF_ST_INFO (STB_LOCAL, STT_FUNC);
 
  elfh->size = size;
 
  elfh->forced_local = 1;
 
  return TRUE;
 
}
 
 
 
/* We're about to redefine H.  Create a symbol to represent H's
 
   current value and size, to help make the disassembly easier
 
   to read.  */
 
 
 
static bfd_boolean
 
mips_elf_create_shadow_symbol (struct bfd_link_info *info,
 
                               struct mips_elf_link_hash_entry *h,
 
                               const char *prefix)
 
{
 
  struct bfd_link_hash_entry *bh;
 
  struct elf_link_hash_entry *elfh;
 
  const char *name;
 
  asection *s;
 
  bfd_vma value;
 
 
 
  /* Read the symbol's value.  */
 
  BFD_ASSERT (h->root.root.type == bfd_link_hash_defined
 
              || h->root.root.type == bfd_link_hash_defweak);
 
  s = h->root.root.u.def.section;
 
  value = h->root.root.u.def.value;
 
 
 
  /* Create a new symbol.  */
 
  name = ACONCAT ((prefix, h->root.root.root.string, NULL));
 
  bh = NULL;
 
  if (!_bfd_generic_link_add_one_symbol (info, s->owner, name,
 
                                         BSF_LOCAL, s, value, NULL,
 
                                         TRUE, FALSE, &bh))
 
    return FALSE;
 
 
 
  /* Make it local and copy the other attributes from H.  */
 
  elfh = (struct elf_link_hash_entry *) bh;
 
  elfh->type = ELF_ST_INFO (STB_LOCAL, ELF_ST_TYPE (h->root.type));
 
  elfh->other = h->root.other;
 
  elfh->size = h->root.size;
 
  elfh->forced_local = 1;
 
  return TRUE;
 
}
 
 
 
/* Return TRUE if relocations in SECTION can refer directly to a MIPS16
 
   function rather than to a hard-float stub.  */
 
 
 
static bfd_boolean
 
section_allows_mips16_refs_p (asection *section)
 
{
 
  const char *name;
 
 
 
  name = bfd_get_section_name (section->owner, section);
 
  return (FN_STUB_P (name)
 
          || CALL_STUB_P (name)
 
          || CALL_FP_STUB_P (name)
 
          || strcmp (name, ".pdr") == 0);
 
}
 
 
 
/* [RELOCS, RELEND) are the relocations against SEC, which is a MIPS16
 
   stub section of some kind.  Return the R_SYMNDX of the target
 
   function, or 0 if we can't decide which function that is.  */
 
 
 
static unsigned long
 
mips16_stub_symndx (asection *sec ATTRIBUTE_UNUSED,
 
                    const Elf_Internal_Rela *relocs,
 
                    const Elf_Internal_Rela *relend)
 
{
 
  const Elf_Internal_Rela *rel;
 
 
 
  /* Trust the first R_MIPS_NONE relocation, if any.  */
 
  for (rel = relocs; rel < relend; rel++)
 
    if (ELF_R_TYPE (sec->owner, rel->r_info) == R_MIPS_NONE)
 
      return ELF_R_SYM (sec->owner, rel->r_info);
 
 
 
  /* Otherwise trust the first relocation, whatever its kind.  This is
 
     the traditional behavior.  */
 
  if (relocs < relend)
 
    return ELF_R_SYM (sec->owner, relocs->r_info);
 
 
 
  return 0;
 
}
 
 
/* Check the mips16 stubs for a particular symbol, and see if we can
/* Check the mips16 stubs for a particular symbol, and see if we can
   discard them.  */
   discard them.  */
 
 
static bfd_boolean
static void
mips_elf_check_mips16_stubs (struct mips_elf_link_hash_entry *h,
mips_elf_check_mips16_stubs (struct bfd_link_info *info,
                             void *data ATTRIBUTE_UNUSED)
                             struct mips_elf_link_hash_entry *h)
{
{
  if (h->root.root.type == bfd_link_hash_warning)
  /* Dynamic symbols must use the standard call interface, in case other
    h = (struct mips_elf_link_hash_entry *) h->root.root.u.i.link;
     objects try to call them.  */
 
  if (h->fn_stub != NULL
 
      && h->root.dynindx != -1)
 
    {
 
      mips_elf_create_shadow_symbol (info, h, ".mips16.");
 
      h->need_fn_stub = TRUE;
 
    }
 
 
  if (h->fn_stub != NULL
  if (h->fn_stub != NULL
      && ! h->need_fn_stub)
      && ! h->need_fn_stub)
    {
    {
      /* We don't need the fn_stub; the only references to this symbol
      /* We don't need the fn_stub; the only references to this symbol
Line 1164... Line 1480...
      h->fn_stub->reloc_count = 0;
      h->fn_stub->reloc_count = 0;
      h->fn_stub->flags |= SEC_EXCLUDE;
      h->fn_stub->flags |= SEC_EXCLUDE;
    }
    }
 
 
  if (h->call_stub != NULL
  if (h->call_stub != NULL
      && h->root.other == STO_MIPS16)
      && ELF_ST_IS_MIPS16 (h->root.other))
    {
    {
      /* We don't need the call_stub; this is a 16 bit function, so
      /* We don't need the call_stub; this is a 16 bit function, so
         calls from other 16 bit functions are OK.  Clobber the size
         calls from other 16 bit functions are OK.  Clobber the size
         to 0 to prevent it from being included in the link.  */
         to 0 to prevent it from being included in the link.  */
      h->call_stub->size = 0;
      h->call_stub->size = 0;
Line 1176... Line 1492...
      h->call_stub->reloc_count = 0;
      h->call_stub->reloc_count = 0;
      h->call_stub->flags |= SEC_EXCLUDE;
      h->call_stub->flags |= SEC_EXCLUDE;
    }
    }
 
 
  if (h->call_fp_stub != NULL
  if (h->call_fp_stub != NULL
      && h->root.other == STO_MIPS16)
      && ELF_ST_IS_MIPS16 (h->root.other))
    {
    {
      /* We don't need the call_stub; this is a 16 bit function, so
      /* We don't need the call_stub; this is a 16 bit function, so
         calls from other 16 bit functions are OK.  Clobber the size
         calls from other 16 bit functions are OK.  Clobber the size
         to 0 to prevent it from being included in the link.  */
         to 0 to prevent it from being included in the link.  */
      h->call_fp_stub->size = 0;
      h->call_fp_stub->size = 0;
      h->call_fp_stub->flags &= ~SEC_RELOC;
      h->call_fp_stub->flags &= ~SEC_RELOC;
      h->call_fp_stub->reloc_count = 0;
      h->call_fp_stub->reloc_count = 0;
      h->call_fp_stub->flags |= SEC_EXCLUDE;
      h->call_fp_stub->flags |= SEC_EXCLUDE;
    }
    }
 
}
 
 
 
/* Hashtable callbacks for mips_elf_la25_stubs.  */
 
 
 
static hashval_t
 
mips_elf_la25_stub_hash (const void *entry_)
 
{
 
  const struct mips_elf_la25_stub *entry;
 
 
 
  entry = (struct mips_elf_la25_stub *) entry_;
 
  return entry->h->root.root.u.def.section->id
 
    + entry->h->root.root.u.def.value;
 
}
 
 
 
static int
 
mips_elf_la25_stub_eq (const void *entry1_, const void *entry2_)
 
{
 
  const struct mips_elf_la25_stub *entry1, *entry2;
 
 
 
  entry1 = (struct mips_elf_la25_stub *) entry1_;
 
  entry2 = (struct mips_elf_la25_stub *) entry2_;
 
  return ((entry1->h->root.root.u.def.section
 
           == entry2->h->root.root.u.def.section)
 
          && (entry1->h->root.root.u.def.value
 
              == entry2->h->root.root.u.def.value));
 
}
 
 
 
/* Called by the linker to set up the la25 stub-creation code.  FN is
 
   the linker's implementation of add_stub_function.  Return true on
 
   success.  */
 
 
 
bfd_boolean
 
_bfd_mips_elf_init_stubs (struct bfd_link_info *info,
 
                          asection *(*fn) (const char *, asection *,
 
                                           asection *))
 
{
 
  struct mips_elf_link_hash_table *htab;
 
 
 
  htab = mips_elf_hash_table (info);
 
  htab->add_stub_section = fn;
 
  htab->la25_stubs = htab_try_create (1, mips_elf_la25_stub_hash,
 
                                      mips_elf_la25_stub_eq, NULL);
 
  if (htab->la25_stubs == NULL)
 
    return FALSE;
 
 
 
  return TRUE;
 
}
 
 
 
/* Return true if H is a locally-defined PIC function, in the sense
 
   that it might need $25 to be valid on entry.  Note that MIPS16
 
   functions never need $25 to be valid on entry; they set up $gp
 
   using PC-relative instructions instead.  */
 
 
 
static bfd_boolean
 
mips_elf_local_pic_function_p (struct mips_elf_link_hash_entry *h)
 
{
 
  return ((h->root.root.type == bfd_link_hash_defined
 
           || h->root.root.type == bfd_link_hash_defweak)
 
          && h->root.def_regular
 
          && !bfd_is_abs_section (h->root.root.u.def.section)
 
          && !ELF_ST_IS_MIPS16 (h->root.other)
 
          && (PIC_OBJECT_P (h->root.root.u.def.section->owner)
 
              || ELF_ST_IS_MIPS_PIC (h->root.other)));
 
}
 
 
 
/* STUB describes an la25 stub that we have decided to implement
 
   by inserting an LUI/ADDIU pair before the target function.
 
   Create the section and redirect the function symbol to it.  */
 
 
 
static bfd_boolean
 
mips_elf_add_la25_intro (struct mips_elf_la25_stub *stub,
 
                         struct bfd_link_info *info)
 
{
 
  struct mips_elf_link_hash_table *htab;
 
  char *name;
 
  asection *s, *input_section;
 
  unsigned int align;
 
 
 
  htab = mips_elf_hash_table (info);
 
 
 
  /* Create a unique name for the new section.  */
 
  name = bfd_malloc (11 + sizeof (".text.stub."));
 
  if (name == NULL)
 
    return FALSE;
 
  sprintf (name, ".text.stub.%d", (int) htab_elements (htab->la25_stubs));
 
 
 
  /* Create the section.  */
 
  input_section = stub->h->root.root.u.def.section;
 
  s = htab->add_stub_section (name, input_section,
 
                              input_section->output_section);
 
  if (s == NULL)
 
    return FALSE;
 
 
 
  /* Make sure that any padding goes before the stub.  */
 
  align = input_section->alignment_power;
 
  if (!bfd_set_section_alignment (s->owner, s, align))
 
    return FALSE;
 
  if (align > 3)
 
    s->size = (1 << align) - 8;
 
 
 
  /* Create a symbol for the stub.  */
 
  mips_elf_create_stub_symbol (info, stub->h, ".pic.", s, s->size, 8);
 
  stub->stub_section = s;
 
  stub->offset = s->size;
 
 
 
  /* Allocate room for it.  */
 
  s->size += 8;
 
  return TRUE;
 
}
 
 
 
/* STUB describes an la25 stub that we have decided to implement
 
   with a separate trampoline.  Allocate room for it and redirect
 
   the function symbol to it.  */
 
 
 
static bfd_boolean
 
mips_elf_add_la25_trampoline (struct mips_elf_la25_stub *stub,
 
                              struct bfd_link_info *info)
 
{
 
  struct mips_elf_link_hash_table *htab;
 
  asection *s;
 
 
 
  htab = mips_elf_hash_table (info);
 
 
 
  /* Create a trampoline section, if we haven't already.  */
 
  s = htab->strampoline;
 
  if (s == NULL)
 
    {
 
      asection *input_section = stub->h->root.root.u.def.section;
 
      s = htab->add_stub_section (".text", NULL,
 
                                  input_section->output_section);
 
      if (s == NULL || !bfd_set_section_alignment (s->owner, s, 4))
 
        return FALSE;
 
      htab->strampoline = s;
 
    }
 
 
 
  /* Create a symbol for the stub.  */
 
  mips_elf_create_stub_symbol (info, stub->h, ".pic.", s, s->size, 16);
 
  stub->stub_section = s;
 
  stub->offset = s->size;
 
 
 
  /* Allocate room for it.  */
 
  s->size += 16;
 
  return TRUE;
 
}
 
 
 
/* H describes a symbol that needs an la25 stub.  Make sure that an
 
   appropriate stub exists and point H at it.  */
 
 
 
static bfd_boolean
 
mips_elf_add_la25_stub (struct bfd_link_info *info,
 
                        struct mips_elf_link_hash_entry *h)
 
{
 
  struct mips_elf_link_hash_table *htab;
 
  struct mips_elf_la25_stub search, *stub;
 
  bfd_boolean use_trampoline_p;
 
  asection *s;
 
  bfd_vma value;
 
  void **slot;
 
 
 
  /* Prefer to use LUI/ADDIU stubs if the function is at the beginning
 
     of the section and if we would need no more than 2 nops.  */
 
  s = h->root.root.u.def.section;
 
  value = h->root.root.u.def.value;
 
  use_trampoline_p = (value != 0 || s->alignment_power > 4);
 
 
 
  /* Describe the stub we want.  */
 
  search.stub_section = NULL;
 
  search.offset = 0;
 
  search.h = h;
 
 
 
  /* See if we've already created an equivalent stub.  */
 
  htab = mips_elf_hash_table (info);
 
  slot = htab_find_slot (htab->la25_stubs, &search, INSERT);
 
  if (slot == NULL)
 
    return FALSE;
 
 
 
  stub = (struct mips_elf_la25_stub *) *slot;
 
  if (stub != NULL)
 
    {
 
      /* We can reuse the existing stub.  */
 
      h->la25_stub = stub;
 
      return TRUE;
 
    }
 
 
 
  /* Create a permanent copy of ENTRY and add it to the hash table.  */
 
  stub = bfd_malloc (sizeof (search));
 
  if (stub == NULL)
 
    return FALSE;
 
  *stub = search;
 
  *slot = stub;
 
 
 
  h->la25_stub = stub;
 
  return (use_trampoline_p
 
          ? mips_elf_add_la25_trampoline (stub, info)
 
          : mips_elf_add_la25_intro (stub, info));
 
}
 
 
 
/* A mips_elf_link_hash_traverse callback that is called before sizing
 
   sections.  DATA points to a mips_htab_traverse_info structure.  */
 
 
 
static bfd_boolean
 
mips_elf_check_symbols (struct mips_elf_link_hash_entry *h, void *data)
 
{
 
  struct mips_htab_traverse_info *hti;
 
 
 
  hti = (struct mips_htab_traverse_info *) data;
 
  if (h->root.root.type == bfd_link_hash_warning)
 
    h = (struct mips_elf_link_hash_entry *) h->root.root.u.i.link;
 
 
 
  if (!hti->info->relocatable)
 
    mips_elf_check_mips16_stubs (hti->info, h);
 
 
 
  if (mips_elf_local_pic_function_p (h))
 
    {
 
      /* H is a function that might need $25 to be valid on entry.
 
         If we're creating a non-PIC relocatable object, mark H as
 
         being PIC.  If we're creating a non-relocatable object with
 
         non-PIC branches and jumps to H, make sure that H has an la25
 
         stub.  */
 
      if (hti->info->relocatable)
 
        {
 
          if (!PIC_OBJECT_P (hti->output_bfd))
 
            h->root.other = ELF_ST_SET_MIPS_PIC (h->root.other);
 
        }
 
      else if (h->has_nonpic_branches && !mips_elf_add_la25_stub (hti->info, h))
 
        {
 
          hti->error = TRUE;
 
          return FALSE;
 
        }
 
    }
  return TRUE;
  return TRUE;
}
}


/* R_MIPS16_26 is used for the mips16 jal and jalx instructions.
/* R_MIPS16_26 is used for the mips16 jal and jalx instructions.
   Most mips16 instructions are 16 bits, but these instructions
   Most mips16 instructions are 16 bits, but these instructions
Line 1249... Line 1794...
   (((A < 2) | ((P + 4) & 0xf0000000) + S) >> 2)
   (((A < 2) | ((P + 4) & 0xf0000000) + S) >> 2)
   When producing a fully linked file, the calculation is
   When producing a fully linked file, the calculation is
   let R = (((A < 2) | ((P + 4) & 0xf0000000) + S) >> 2)
   let R = (((A < 2) | ((P + 4) & 0xf0000000) + S) >> 2)
   ((R & 0x1f0000) << 5) | ((R & 0x3e00000) >> 5) | (R & 0xffff)
   ((R & 0x1f0000) << 5) | ((R & 0x3e00000) >> 5) | (R & 0xffff)
 
 
   R_MIPS16_GPREL is used for GP-relative addressing in mips16
   The table below lists the other MIPS16 instruction relocations.
   mode.  A typical instruction will have a format like this:
   Each one is calculated in the same way as the non-MIPS16 relocation
 
   given on the right, but using the extended MIPS16 layout of 16-bit
 
   immediate fields:
 
 
 
        R_MIPS16_GPREL          R_MIPS_GPREL16
 
        R_MIPS16_GOT16          R_MIPS_GOT16
 
        R_MIPS16_CALL16         R_MIPS_CALL16
 
        R_MIPS16_HI16           R_MIPS_HI16
 
        R_MIPS16_LO16           R_MIPS_LO16
 
 
 
   A typical instruction will have a format like this:
 
 
   +--------------+--------------------------------+
   +--------------+--------------------------------+
   |    EXTEND    |     Imm 10:5    |   Imm 15:11  |
   |    EXTEND    |     Imm 10:5    |   Imm 15:11  |
   +--------------+--------------------------------+
   +--------------+--------------------------------+
   |    Major     |   rx   |   ry   |   Imm  4:0   |
   |    Major     |   rx   |   ry   |   Imm  4:0   |
   +--------------+--------------------------------+
   +--------------+--------------------------------+
 
 
   EXTEND is the five bit value 11110.  Major is the instruction
   EXTEND is the five bit value 11110.  Major is the instruction
   opcode.
   opcode.
 
 
   This is handled exactly like R_MIPS_GPREL16, except that the
   All we need to do here is shuffle the bits appropriately.
   addend is retrieved and stored as shown in this diagram; that
   As above, the two 16-bit halves must be swapped on a
   is, the Imm fields above replace the V-rel16 field.
   little-endian system.  */
 
 
   All we need to do here is shuffle the bits appropriately.  As
static inline bfd_boolean
   above, the two 16-bit halves must be swapped on a
mips16_reloc_p (int r_type)
   little-endian system.
{
 
  switch (r_type)
   R_MIPS16_HI16 and R_MIPS16_LO16 are used in mips16 mode to
    {
   access data when neither GP-relative nor PC-relative addressing
    case R_MIPS16_26:
   can be used.  They are handled like R_MIPS_HI16 and R_MIPS_LO16,
    case R_MIPS16_GPREL:
   except that the addend is retrieved and stored as shown above
    case R_MIPS16_GOT16:
   for R_MIPS16_GPREL.
    case R_MIPS16_CALL16:
  */
    case R_MIPS16_HI16:
 
    case R_MIPS16_LO16:
 
      return TRUE;
 
 
 
    default:
 
      return FALSE;
 
    }
 
}
 
 
 
static inline bfd_boolean
 
got16_reloc_p (int r_type)
 
{
 
  return r_type == R_MIPS_GOT16 || r_type == R_MIPS16_GOT16;
 
}
 
 
 
static inline bfd_boolean
 
call16_reloc_p (int r_type)
 
{
 
  return r_type == R_MIPS_CALL16 || r_type == R_MIPS16_CALL16;
 
}
 
 
 
static inline bfd_boolean
 
hi16_reloc_p (int r_type)
 
{
 
  return r_type == R_MIPS_HI16 || r_type == R_MIPS16_HI16;
 
}
 
 
 
static inline bfd_boolean
 
lo16_reloc_p (int r_type)
 
{
 
  return r_type == R_MIPS_LO16 || r_type == R_MIPS16_LO16;
 
}
 
 
 
static inline bfd_boolean
 
mips16_call_reloc_p (int r_type)
 
{
 
  return r_type == R_MIPS16_26 || r_type == R_MIPS16_CALL16;
 
}
 
 
void
void
_bfd_mips16_elf_reloc_unshuffle (bfd *abfd, int r_type,
_bfd_mips16_elf_reloc_unshuffle (bfd *abfd, int r_type,
                                 bfd_boolean jal_shuffle, bfd_byte *data)
                                 bfd_boolean jal_shuffle, bfd_byte *data)
{
{
  bfd_vma extend, insn, val;
  bfd_vma extend, insn, val;
 
 
  if (r_type != R_MIPS16_26 && r_type != R_MIPS16_GPREL
  if (!mips16_reloc_p (r_type))
      && r_type != R_MIPS16_HI16 && r_type != R_MIPS16_LO16)
 
    return;
    return;
 
 
  /* Pick up the mips16 extend instruction and the real instruction.  */
  /* Pick up the mips16 extend instruction and the real instruction.  */
  extend = bfd_get_16 (abfd, data);
  extend = bfd_get_16 (abfd, data);
  insn = bfd_get_16 (abfd, data + 2);
  insn = bfd_get_16 (abfd, data + 2);
Line 1308... Line 1900...
_bfd_mips16_elf_reloc_shuffle (bfd *abfd, int r_type,
_bfd_mips16_elf_reloc_shuffle (bfd *abfd, int r_type,
                               bfd_boolean jal_shuffle, bfd_byte *data)
                               bfd_boolean jal_shuffle, bfd_byte *data)
{
{
  bfd_vma extend, insn, val;
  bfd_vma extend, insn, val;
 
 
  if (r_type != R_MIPS16_26 && r_type != R_MIPS16_GPREL
  if (!mips16_reloc_p (r_type))
      && r_type != R_MIPS16_HI16 && r_type != R_MIPS16_LO16)
 
    return;
    return;
 
 
  val = bfd_get_32 (abfd, data);
  val = bfd_get_32 (abfd, data);
  if (r_type == R_MIPS16_26)
  if (r_type == R_MIPS16_26)
    {
    {
Line 1438... Line 2029...
    reloc_entry->address += input_section->output_offset;
    reloc_entry->address += input_section->output_offset;
 
 
  return bfd_reloc_ok;
  return bfd_reloc_ok;
}
}
 
 
/* A howto special_function for REL R_MIPS_GOT16 relocations.  This is just
/* A howto special_function for REL R_MIPS*_GOT16 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_MIPS_HI16 when applied to local symbols.  */
   treated in the same as R_MIPS_HI16 when applied to local symbols.  */
 
 
bfd_reloc_status_type
bfd_reloc_status_type
_bfd_mips_elf_got16_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
_bfd_mips_elf_got16_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
Line 1487... Line 2078...
      bfd_reloc_status_type ret;
      bfd_reloc_status_type ret;
      struct mips_hi16 *hi;
      struct mips_hi16 *hi;
 
 
      hi = mips_hi16_list;
      hi = mips_hi16_list;
 
 
      /* R_MIPS_GOT16 relocations are something of a special case.  We
      /* R_MIPS*_GOT16 relocations are something of a special case.  We
         want to install the addend in the same way as for a R_MIPS_HI16
         want to install the addend in the same way as for a R_MIPS*_HI16
         relocation (with a rightshift of 16).  However, since GOT16
         relocation (with a rightshift of 16).  However, since GOT16
         relocations can also be used with global symbols, their howto
         relocations can also be used with global symbols, their howto
         has a rightshift of 0.  */
         has a rightshift of 0.  */
      if (hi->rel.howto->type == R_MIPS_GOT16)
      if (hi->rel.howto->type == R_MIPS_GOT16)
        hi->rel.howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, R_MIPS_HI16, FALSE);
        hi->rel.howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, R_MIPS_HI16, FALSE);
 
      else if (hi->rel.howto->type == R_MIPS16_GOT16)
 
        hi->rel.howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, R_MIPS16_HI16, FALSE);
 
 
      /* VALLO is a signed 16-bit number.  Bias it by 0x8000 so that any
      /* VALLO is a signed 16-bit number.  Bias it by 0x8000 so that any
         carry or borrow will induce a change of +1 or -1 in the high part.  */
         carry or borrow will induce a change of +1 or -1 in the high part.  */
      hi->rel.addend += (vallo + 0x8000) & 0xffff;
      hi->rel.addend += (vallo + 0x8000) & 0xffff;
 
 
Line 1921... Line 2514...
                              + sec->output_offset
                              + sec->output_offset
                              + output_section->vma);
                              + output_section->vma);
      else
      else
        h->esym.asym.value = 0;
        h->esym.asym.value = 0;
    }
    }
  else if (h->root.needs_plt)
  else
    {
    {
      struct mips_elf_link_hash_entry *hd = h;
      struct mips_elf_link_hash_entry *hd = h;
      bfd_boolean no_fn_stub = h->no_fn_stub;
 
 
 
      while (hd->root.root.type == bfd_link_hash_indirect)
      while (hd->root.root.type == bfd_link_hash_indirect)
        {
 
          hd = (struct mips_elf_link_hash_entry *)h->root.root.u.i.link;
          hd = (struct mips_elf_link_hash_entry *)h->root.root.u.i.link;
          no_fn_stub = no_fn_stub || hd->no_fn_stub;
 
        }
 
 
 
      if (!no_fn_stub)
      if (hd->needs_lazy_stub)
        {
        {
          /* Set type and value for a symbol with a function stub.  */
          /* Set type and value for a symbol with a function stub.  */
          h->esym.asym.st = stProc;
          h->esym.asym.st = stProc;
          sec = hd->root.root.u.def.section;
          sec = hd->root.root.u.def.section;
          if (sec == NULL)
          if (sec == NULL)
Line 2114... Line 2703...
        return NULL;
        return NULL;
    }
    }
  return sreloc;
  return sreloc;
}
}
 
 
/* Returns the GOT section for ABFD.  */
 
 
 
static asection *
 
mips_elf_got_section (bfd *abfd, bfd_boolean maybe_excluded)
 
{
 
  asection *sgot = bfd_get_section_by_name (abfd, ".got");
 
  if (sgot == NULL
 
      || (! maybe_excluded && (sgot->flags & SEC_EXCLUDE) != 0))
 
    return NULL;
 
  return sgot;
 
}
 
 
 
/* Returns the GOT information associated with the link indicated by
 
   INFO.  If SGOTP is non-NULL, it is filled in with the GOT
 
   section.  */
 
 
 
static struct mips_got_info *
 
mips_elf_got_info (bfd *abfd, asection **sgotp)
 
{
 
  asection *sgot;
 
  struct mips_got_info *g;
 
 
 
  sgot = mips_elf_got_section (abfd, TRUE);
 
  BFD_ASSERT (sgot != NULL);
 
  BFD_ASSERT (mips_elf_section_data (sgot) != NULL);
 
  g = mips_elf_section_data (sgot)->u.got_info;
 
  BFD_ASSERT (g != NULL);
 
 
 
  if (sgotp)
 
    *sgotp = (sgot->flags & SEC_EXCLUDE) == 0 ? sgot : NULL;
 
 
 
  return g;
 
}
 
 
 
/* Count the number of relocations needed for a TLS GOT entry, with
/* Count the number of relocations needed for a TLS GOT entry, with
   access types from TLS_TYPE, and symbol H (or a local symbol if H
   access types from TLS_TYPE, and symbol H (or a local symbol if H
   is NULL).  */
   is NULL).  */
 
 
static int
static int
Line 2243... Line 2798...
/* Output a simple dynamic relocation into SRELOC.  */
/* Output a simple dynamic relocation into SRELOC.  */
 
 
static void
static void
mips_elf_output_dynamic_relocation (bfd *output_bfd,
mips_elf_output_dynamic_relocation (bfd *output_bfd,
                                    asection *sreloc,
                                    asection *sreloc,
 
                                    unsigned long reloc_index,
                                    unsigned long indx,
                                    unsigned long indx,
                                    int r_type,
                                    int r_type,
                                    bfd_vma offset)
                                    bfd_vma offset)
{
{
  Elf_Internal_Rela rel[3];
  Elf_Internal_Rela rel[3];
Line 2259... Line 2815...
  if (ABI_64_P (output_bfd))
  if (ABI_64_P (output_bfd))
    {
    {
      (*get_elf_backend_data (output_bfd)->s->swap_reloc_out)
      (*get_elf_backend_data (output_bfd)->s->swap_reloc_out)
        (output_bfd, &rel[0],
        (output_bfd, &rel[0],
         (sreloc->contents
         (sreloc->contents
          + sreloc->reloc_count * sizeof (Elf64_Mips_External_Rel)));
          + reloc_index * sizeof (Elf64_Mips_External_Rel)));
    }
    }
  else
  else
    bfd_elf32_swap_reloc_out
    bfd_elf32_swap_reloc_out
      (output_bfd, &rel[0],
      (output_bfd, &rel[0],
       (sreloc->contents
       (sreloc->contents
        + sreloc->reloc_count * sizeof (Elf32_External_Rel)));
        + reloc_index * sizeof (Elf32_External_Rel)));
  ++sreloc->reloc_count;
 
}
}
 
 
/* Initialize a set of TLS GOT entries for one symbol.  */
/* Initialize a set of TLS GOT entries for one symbol.  */
 
 
static void
static void
Line 2278... Line 2833...
                               unsigned char *tls_type_p,
                               unsigned char *tls_type_p,
                               struct bfd_link_info *info,
                               struct bfd_link_info *info,
                               struct mips_elf_link_hash_entry *h,
                               struct mips_elf_link_hash_entry *h,
                               bfd_vma value)
                               bfd_vma value)
{
{
 
  struct mips_elf_link_hash_table *htab;
  int indx;
  int indx;
  asection *sreloc, *sgot;
  asection *sreloc, *sgot;
  bfd_vma offset, offset2;
  bfd_vma offset, offset2;
  bfd *dynobj;
 
  bfd_boolean need_relocs = FALSE;
  bfd_boolean need_relocs = FALSE;
 
 
  dynobj = elf_hash_table (info)->dynobj;
  htab = mips_elf_hash_table (info);
  sgot = mips_elf_got_section (dynobj, FALSE);
  sgot = htab->sgot;
 
 
  indx = 0;
  indx = 0;
  if (h != NULL)
  if (h != NULL)
    {
    {
      bfd_boolean dyn = elf_hash_table (info)->dynamic_sections_created;
      bfd_boolean dyn = elf_hash_table (info)->dynamic_sections_created;
Line 2324... Line 2879...
      offset2 = offset + MIPS_ELF_GOT_SIZE (abfd);
      offset2 = offset + MIPS_ELF_GOT_SIZE (abfd);
 
 
      if (need_relocs)
      if (need_relocs)
        {
        {
          mips_elf_output_dynamic_relocation
          mips_elf_output_dynamic_relocation
            (abfd, sreloc, indx,
            (abfd, sreloc, sreloc->reloc_count++, indx,
             ABI_64_P (abfd) ? R_MIPS_TLS_DTPMOD64 : R_MIPS_TLS_DTPMOD32,
             ABI_64_P (abfd) ? R_MIPS_TLS_DTPMOD64 : R_MIPS_TLS_DTPMOD32,
             sgot->output_offset + sgot->output_section->vma + offset);
             sgot->output_offset + sgot->output_section->vma + offset);
 
 
          if (indx)
          if (indx)
            mips_elf_output_dynamic_relocation
            mips_elf_output_dynamic_relocation
              (abfd, sreloc, indx,
              (abfd, sreloc, sreloc->reloc_count++, indx,
               ABI_64_P (abfd) ? R_MIPS_TLS_DTPREL64 : R_MIPS_TLS_DTPREL32,
               ABI_64_P (abfd) ? R_MIPS_TLS_DTPREL64 : R_MIPS_TLS_DTPREL32,
               sgot->output_offset + sgot->output_section->vma + offset2);
               sgot->output_offset + sgot->output_section->vma + offset2);
          else
          else
            MIPS_ELF_PUT_WORD (abfd, value - dtprel_base (info),
            MIPS_ELF_PUT_WORD (abfd, value - dtprel_base (info),
                               sgot->contents + offset2);
                               sgot->contents + offset2);
Line 2363... Line 2918...
          else
          else
            MIPS_ELF_PUT_WORD (abfd, 0,
            MIPS_ELF_PUT_WORD (abfd, 0,
                               sgot->contents + offset);
                               sgot->contents + offset);
 
 
          mips_elf_output_dynamic_relocation
          mips_elf_output_dynamic_relocation
            (abfd, sreloc, indx,
            (abfd, sreloc, sreloc->reloc_count++, indx,
             ABI_64_P (abfd) ? R_MIPS_TLS_TPREL64 : R_MIPS_TLS_TPREL32,
             ABI_64_P (abfd) ? R_MIPS_TLS_TPREL64 : R_MIPS_TLS_TPREL32,
             sgot->output_offset + sgot->output_section->vma + offset);
             sgot->output_offset + sgot->output_section->vma + offset);
        }
        }
      else
      else
        MIPS_ELF_PUT_WORD (abfd, value - tprel_base (info),
        MIPS_ELF_PUT_WORD (abfd, value - tprel_base (info),
Line 2385... Line 2940...
      if (!info->shared)
      if (!info->shared)
        MIPS_ELF_PUT_WORD (abfd, 1,
        MIPS_ELF_PUT_WORD (abfd, 1,
                           sgot->contents + got_offset);
                           sgot->contents + got_offset);
      else
      else
        mips_elf_output_dynamic_relocation
        mips_elf_output_dynamic_relocation
          (abfd, sreloc, indx,
          (abfd, sreloc, sreloc->reloc_count++, indx,
           ABI_64_P (abfd) ? R_MIPS_TLS_DTPMOD64 : R_MIPS_TLS_DTPMOD32,
           ABI_64_P (abfd) ? R_MIPS_TLS_DTPMOD64 : R_MIPS_TLS_DTPMOD32,
           sgot->output_offset + sgot->output_section->vma + got_offset);
           sgot->output_offset + sgot->output_section->vma + got_offset);
    }
    }
 
 
  *tls_type_p |= GOT_TLS_DONE;
  *tls_type_p |= GOT_TLS_DONE;
Line 2446... Line 3001...
  struct mips_elf_link_hash_table *htab;
  struct mips_elf_link_hash_table *htab;
 
 
  htab = mips_elf_hash_table (info);
  htab = mips_elf_hash_table (info);
  BFD_ASSERT (h->plt.offset != (bfd_vma) -1);
  BFD_ASSERT (h->plt.offset != (bfd_vma) -1);
 
 
 
  /* This function only works for VxWorks, because a non-VxWorks .got.plt
 
     section starts with reserved entries.  */
 
  BFD_ASSERT (htab->is_vxworks);
 
 
  /* Calculate the index of the symbol's PLT entry.  */
  /* Calculate the index of the symbol's PLT entry.  */
  plt_index = (h->plt.offset - htab->plt_header_size) / htab->plt_entry_size;
  plt_index = (h->plt.offset - htab->plt_header_size) / htab->plt_entry_size;
 
 
  /* Calculate the address of the associated .got.plt entry.  */
  /* Calculate the address of the associated .got.plt entry.  */
  got_address = (htab->sgotplt->output_section->vma
  got_address = (htab->sgotplt->output_section->vma
Line 2472... Line 3031...
static bfd_vma
static bfd_vma
mips_elf_local_got_index (bfd *abfd, bfd *ibfd, struct bfd_link_info *info,
mips_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 mips_elf_link_hash_entry *h, int r_type)
                          struct mips_elf_link_hash_entry *h, int r_type)
{
{
  asection *sgot;
  struct mips_elf_link_hash_table *htab;
  struct mips_got_info *g;
 
  struct mips_got_entry *entry;
  struct mips_got_entry *entry;
 
 
  g = mips_elf_got_info (elf_hash_table (info)->dynobj, &sgot);
  htab = mips_elf_hash_table (info);
 
  entry = mips_elf_create_local_got_entry (abfd, info, ibfd, value,
  entry = mips_elf_create_local_got_entry (abfd, info, ibfd, g, sgot,
                                           r_symndx, h, r_type);
                                           value, r_symndx, h, r_type);
 
  if (!entry)
  if (!entry)
    return MINUS_ONE;
    return MINUS_ONE;
 
 
  if (TLS_RELOC_P (r_type))
  if (TLS_RELOC_P (r_type))
    {
    {
      if (entry->symndx == -1 && g->next == NULL)
      if (entry->symndx == -1 && htab->got_info->next == NULL)
        /* A type (3) entry in the single-GOT case.  We use the symbol's
        /* A type (3) entry in the single-GOT case.  We use the symbol's
           hash table entry to track the index.  */
           hash table entry to track the index.  */
        return mips_tls_got_index (abfd, h->tls_got_offset, &h->tls_type,
        return mips_tls_got_index (abfd, h->tls_got_offset, &h->tls_type,
                                   r_type, info, h, value);
                                   r_type, info, h, value);
      else
      else
Line 2504... Line 3061...
 
 
static bfd_vma
static bfd_vma
mips_elf_global_got_index (bfd *abfd, bfd *ibfd, struct elf_link_hash_entry *h,
mips_elf_global_got_index (bfd *abfd, bfd *ibfd, struct elf_link_hash_entry *h,
                           int r_type, struct bfd_link_info *info)
                           int r_type, struct bfd_link_info *info)
{
{
 
  struct mips_elf_link_hash_table *htab;
  bfd_vma index;
  bfd_vma index;
  asection *sgot;
 
  struct mips_got_info *g, *gg;
  struct mips_got_info *g, *gg;
  long global_got_dynindx = 0;
  long global_got_dynindx = 0;
 
 
  gg = g = mips_elf_got_info (abfd, &sgot);
  htab = mips_elf_hash_table (info);
 
  gg = g = htab->got_info;
  if (g->bfd2got && ibfd)
  if (g->bfd2got && ibfd)
    {
    {
      struct mips_got_entry e, *p;
      struct mips_got_entry e, *p;
 
 
      BFD_ASSERT (h->dynindx >= 0);
      BFD_ASSERT (h->dynindx >= 0);
Line 2575... Line 3133...
         offset.  */
         offset.  */
      BFD_ASSERT (h->dynindx >= global_got_dynindx);
      BFD_ASSERT (h->dynindx >= global_got_dynindx);
      index = ((h->dynindx - global_got_dynindx + g->local_gotno)
      index = ((h->dynindx - global_got_dynindx + g->local_gotno)
               * MIPS_ELF_GOT_SIZE (abfd));
               * MIPS_ELF_GOT_SIZE (abfd));
    }
    }
  BFD_ASSERT (index < sgot->size);
  BFD_ASSERT (index < htab->sgot->size);
 
 
  return index;
  return index;
}
}
 
 
/* Find a GOT page entry that points to within 32KB of VALUE.  These
/* Find a GOT page entry that points to within 32KB of VALUE.  These
Line 2590... Line 3148...
 
 
static bfd_vma
static bfd_vma
mips_elf_got_page (bfd *abfd, bfd *ibfd, struct bfd_link_info *info,
mips_elf_got_page (bfd *abfd, bfd *ibfd, struct bfd_link_info *info,
                   bfd_vma value, bfd_vma *offsetp)
                   bfd_vma value, bfd_vma *offsetp)
{
{
  asection *sgot;
 
  struct mips_got_info *g;
 
  bfd_vma page, index;
  bfd_vma page, index;
  struct mips_got_entry *entry;
  struct mips_got_entry *entry;
 
 
  g = mips_elf_got_info (elf_hash_table (info)->dynobj, &sgot);
 
 
 
  page = (value + 0x8000) & ~(bfd_vma) 0xffff;
  page = (value + 0x8000) & ~(bfd_vma) 0xffff;
  entry = mips_elf_create_local_got_entry (abfd, info, ibfd, g, sgot,
  entry = mips_elf_create_local_got_entry (abfd, info, ibfd, page, 0,
                                           page, 0, NULL, R_MIPS_GOT_PAGE);
                                           NULL, R_MIPS_GOT_PAGE);
 
 
  if (!entry)
  if (!entry)
    return MINUS_ONE;
    return MINUS_ONE;
 
 
  index = entry->gotidx;
  index = entry->gotidx;
Line 2612... Line 3166...
    *offsetp = value - entry->d.address;
    *offsetp = value - entry->d.address;
 
 
  return index;
  return index;
}
}
 
 
/* Find a local GOT entry for an R_MIPS_GOT16 relocation against VALUE.
/* Find a local GOT entry for an R_MIPS*_GOT16 relocation against VALUE.
   EXTERNAL is true if the relocation was against a global symbol
   EXTERNAL is true if the relocation was against a global symbol
   that has been forced local.  */
   that has been forced local.  */
 
 
static bfd_vma
static bfd_vma
mips_elf_got16_entry (bfd *abfd, bfd *ibfd, struct bfd_link_info *info,
mips_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;
 
  struct mips_got_info *g;
 
  struct mips_got_entry *entry;
  struct mips_got_entry *entry;
 
 
  /* GOT16 relocations against local symbols are followed by a LO16
  /* GOT16 relocations against local symbols are followed by a LO16
     relocation; those against global symbols are not.  Thus if the
     relocation; those against global symbols are not.  Thus if the
     symbol was originally local, the GOT16 relocation should load the
     symbol was originally local, the GOT16 relocation should load the
     equivalent of %hi(VALUE), otherwise it should load VALUE itself.  */
     equivalent of %hi(VALUE), otherwise it should load VALUE itself.  */
  if (! external)
  if (! external)
    value = mips_elf_high (value) << 16;
    value = mips_elf_high (value) << 16;
 
 
  g = mips_elf_got_info (elf_hash_table (info)->dynobj, &sgot);
  /* It doesn't matter whether the original relocation was R_MIPS_GOT16,
 
     R_MIPS16_GOT16, R_MIPS_CALL16, etc.  The format of the entry is the
  entry = mips_elf_create_local_got_entry (abfd, info, ibfd, g, sgot,
     same in all cases.  */
                                           value, 0, NULL, R_MIPS_GOT16);
  entry = mips_elf_create_local_got_entry (abfd, info, ibfd, value, 0,
 
                                           NULL, R_MIPS_GOT16);
  if (entry)
  if (entry)
    return entry->gotidx;
    return entry->gotidx;
  else
  else
    return MINUS_ONE;
    return MINUS_ONE;
}
}
 
 
/* Returns the offset for the entry at the INDEXth position
/* Returns the offset for the entry at the INDEXth position
   in the GOT.  */
   in the GOT.  */
 
 
static bfd_vma
static bfd_vma
mips_elf_got_offset_from_index (bfd *dynobj, bfd *output_bfd,
mips_elf_got_offset_from_index (struct bfd_link_info *info, bfd *output_bfd,
                                bfd *input_bfd, bfd_vma index)
                                bfd *input_bfd, bfd_vma index)
{
{
 
  struct mips_elf_link_hash_table *htab;
  asection *sgot;
  asection *sgot;
  bfd_vma gp;
  bfd_vma gp;
  struct mips_got_info *g;
 
 
 
  g = mips_elf_got_info (dynobj, &sgot);
  htab = mips_elf_hash_table (info);
 
  sgot = htab->sgot;
  gp = _bfd_get_gp_value (output_bfd)
  gp = _bfd_get_gp_value (output_bfd)
    + mips_elf_adjust_gp (output_bfd, g, input_bfd);
    + mips_elf_adjust_gp (output_bfd, htab->got_info, input_bfd);
 
 
  return sgot->output_section->vma + sgot->output_offset + index - gp;
  return sgot->output_section->vma + sgot->output_offset + index - gp;
}
}
 
 
/* Create and return a local GOT entry for VALUE, which was calculated
/* Create and return a local GOT entry for VALUE, which was calculated
Line 2666... Line 3220...
   be created.  If R_SYMNDX refers to a TLS symbol, create a TLS entry
   be created.  If R_SYMNDX refers to a TLS symbol, create a TLS entry
   instead.  */
   instead.  */
 
 
static struct mips_got_entry *
static struct mips_got_entry *
mips_elf_create_local_got_entry (bfd *abfd, struct bfd_link_info *info,
mips_elf_create_local_got_entry (bfd *abfd, struct bfd_link_info *info,
                                 bfd *ibfd, struct mips_got_info *gg,
                                 bfd *ibfd, bfd_vma value,
                                 asection *sgot, bfd_vma value,
 
                                 unsigned long r_symndx,
                                 unsigned long r_symndx,
                                 struct mips_elf_link_hash_entry *h,
                                 struct mips_elf_link_hash_entry *h,
                                 int r_type)
                                 int r_type)
{
{
  struct mips_got_entry entry, **loc;
  struct mips_got_entry entry, **loc;
Line 2683... Line 3236...
  entry.abfd = NULL;
  entry.abfd = NULL;
  entry.symndx = -1;
  entry.symndx = -1;
  entry.d.address = value;
  entry.d.address = value;
  entry.tls_type = 0;
  entry.tls_type = 0;
 
 
  g = mips_elf_got_for_ibfd (gg, ibfd);
  g = mips_elf_got_for_ibfd (htab->got_info, ibfd);
  if (g == NULL)
  if (g == NULL)
    {
    {
      g = mips_elf_got_for_ibfd (gg, abfd);
      g = mips_elf_got_for_ibfd (htab->got_info, abfd);
      BFD_ASSERT (g != NULL);
      BFD_ASSERT (g != NULL);
    }
    }
 
 
  /* We might have a symbol, H, if it has been forced local.  Use the
  /* We might have a symbol, H, if it has been forced local.  Use the
     global entry then.  It doesn't matter whether an entry is local
     global entry then.  It doesn't matter whether an entry is local
Line 2747... Line 3300...
      bfd_set_error (bfd_error_bad_value);
      bfd_set_error (bfd_error_bad_value);
      return NULL;
      return NULL;
    }
    }
 
 
  MIPS_ELF_PUT_WORD (abfd, value,
  MIPS_ELF_PUT_WORD (abfd, value,
                     (sgot->contents + entry.gotidx));
                     (htab->sgot->contents + entry.gotidx));
 
 
  /* These GOT entries need a dynamic relocation on VxWorks.  */
  /* These GOT entries need a dynamic relocation on VxWorks.  */
  if (htab->is_vxworks)
  if (htab->is_vxworks)
    {
    {
      Elf_Internal_Rela outrel;
      Elf_Internal_Rela outrel;
      asection *s;
      asection *s;
      bfd_byte *loc;
      bfd_byte *loc;
      bfd_vma got_address;
      bfd_vma got_address;
 
 
      s = mips_elf_rel_dyn_section (info, FALSE);
      s = mips_elf_rel_dyn_section (info, FALSE);
      got_address = (sgot->output_section->vma
      got_address = (htab->sgot->output_section->vma
                     + sgot->output_offset
                     + htab->sgot->output_offset
                     + entry.gotidx);
                     + entry.gotidx);
 
 
      loc = s->contents + (s->reloc_count++ * sizeof (Elf32_External_Rela));
      loc = s->contents + (s->reloc_count++ * sizeof (Elf32_External_Rela));
      outrel.r_offset = got_address;
      outrel.r_offset = got_address;
      outrel.r_info = ELF32_R_INFO (STN_UNDEF, R_MIPS_32);
      outrel.r_info = ELF32_R_INFO (STN_UNDEF, R_MIPS_32);
Line 2772... Line 3325...
    }
    }
 
 
  return *loc;
  return *loc;
}
}
 
 
 
/* Return the number of dynamic section symbols required by OUTPUT_BFD.
 
   The number might be exact or a worst-case estimate, depending on how
 
   much information is available to elf_backend_omit_section_dynsym at
 
   the current linking stage.  */
 
 
 
static bfd_size_type
 
count_section_dynsyms (bfd *output_bfd, struct bfd_link_info *info)
 
{
 
  bfd_size_type count;
 
 
 
  count = 0;
 
  if (info->shared || elf_hash_table (info)->is_relocatable_executable)
 
    {
 
      asection *p;
 
      const struct elf_backend_data *bed;
 
 
 
      bed = get_elf_backend_data (output_bfd);
 
      for (p = output_bfd->sections; p ; p = p->next)
 
        if ((p->flags & SEC_EXCLUDE) == 0
 
            && (p->flags & SEC_ALLOC) != 0
 
            && !(*bed->elf_backend_omit_section_dynsym) (output_bfd, info, p))
 
          ++count;
 
    }
 
  return count;
 
}
 
 
/* 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.  */
   required.  MAX_LOCAL is used to set the number of local symbols
 
   known to be in the dynamic symbol table.  During
 
   _bfd_mips_elf_size_dynamic_sections, this value is 1.  Afterward, the
 
   section symbols are added and the count is higher.  */
 
 
 
static bfd_boolean
static bfd_boolean
mips_elf_sort_hash_table (struct bfd_link_info *info, unsigned long max_local)
mips_elf_sort_hash_table (bfd *abfd, struct bfd_link_info *info)
{
{
 
  struct mips_elf_link_hash_table *htab;
  struct mips_elf_hash_sort_data hsd;
  struct mips_elf_hash_sort_data hsd;
  struct mips_got_info *g;
  struct mips_got_info *g;
  bfd *dynobj;
 
 
 
  dynobj = elf_hash_table (info)->dynobj;
  if (elf_hash_table (info)->dynsymcount == 0)
 
    return TRUE;
 
 
  g = mips_elf_got_info (dynobj, NULL);
  htab = mips_elf_hash_table (info);
 
  g = htab->got_info;
 
  if (g == NULL)
 
    return TRUE;
 
 
  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
    /* In the multi-got case, assigned_gotno of the master got_info
    = (elf_hash_table (info)->dynsymcount - g->reloc_only_gotno);
       indicate the number of entries that aren't referenced in the
  hsd.max_non_got_dynindx = count_section_dynsyms (abfd, info) + 1;
       primary GOT, but that must have entries because there are
 
       dynamic relocations that reference it.  Since they aren't
 
       referenced, we move them to the end of the GOT, so that they
 
       don't prevent other entries that are referenced from getting
 
       too large offsets.  */
 
    - (g->next ? g->assigned_gotno : 0);
 
  hsd.max_non_got_dynindx = max_local;
 
  mips_elf_link_hash_traverse (((struct mips_elf_link_hash_table *)
  mips_elf_link_hash_traverse (((struct mips_elf_link_hash_table *)
                                elf_hash_table (info)),
                                elf_hash_table (info)),
                               mips_elf_sort_hash_table_f,
                               mips_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);
 
  BFD_ASSERT (elf_hash_table (info)->dynsymcount - hsd.min_got_dynindx
 
              == g->global_gotno);
 
 
  /* 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;
 
 
Line 2837... Line 3411...
  /* Symbols without dynamic symbol table entries aren't interesting
  /* Symbols without dynamic symbol table entries aren't interesting
     at all.  */
     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
  switch (h->global_got_area)
     referenced are marked with got offset 2.  Those that are
 
     referenced get a 1, and those that don't need GOT entries get
 
     -1.  Forced local symbols may also be marked with got offset 1,
 
     but are never given global GOT entries.  */
 
  if (h->root.got.offset == 2)
 
    {
    {
 
    case GGA_NONE:
 
      h->root.dynindx = hsd->max_non_got_dynindx++;
 
      break;
 
 
 
    case GGA_NORMAL:
      BFD_ASSERT (h->tls_type == GOT_NORMAL);
      BFD_ASSERT (h->tls_type == GOT_NORMAL);
 
 
      if (hsd->max_unref_got_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;
      h->root.dynindx = hsd->max_unref_got_dynindx++;
      break;
    }
 
  else if (h->root.got.offset != 1 || h->forced_local)
    case GGA_RELOC_ONLY:
    h->root.dynindx = hsd->max_non_got_dynindx++;
 
  else
 
    {
 
      BFD_ASSERT (h->tls_type == GOT_NORMAL);
      BFD_ASSERT (h->tls_type == GOT_NORMAL);
 
 
      h->root.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++;
 
      break;
    }
    }
 
 
  return TRUE;
  return TRUE;
}
}
 
 
Line 2870... Line 3443...
   posterity.  */
   posterity.  */
 
 
static bfd_boolean
static bfd_boolean
mips_elf_record_global_got_symbol (struct elf_link_hash_entry *h,
mips_elf_record_global_got_symbol (struct elf_link_hash_entry *h,
                                   bfd *abfd, struct bfd_link_info *info,
                                   bfd *abfd, struct bfd_link_info *info,
                                   struct mips_got_info *g,
 
                                   unsigned char tls_flag)
                                   unsigned char tls_flag)
{
{
 
  struct mips_elf_link_hash_table *htab;
 
  struct mips_elf_link_hash_entry *hmips;
  struct mips_got_entry entry, **loc;
  struct mips_got_entry entry, **loc;
 
  struct mips_got_info *g;
 
 
 
  htab = mips_elf_hash_table (info);
 
  hmips = (struct mips_elf_link_hash_entry *) h;
 
 
  /* A global symbol in the GOT must also be in the dynamic symbol
  /* A global symbol in the GOT must also be in the dynamic symbol
     table.  */
     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:
          _bfd_mips_elf_hide_symbol (info, h, TRUE);
          _bfd_elf_link_hash_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;
    }
    }
 
 
  /* Make sure we have a GOT to put this entry into.  */
  /* Make sure we have a GOT to put this entry into.  */
 
  g = htab->got_info;
  BFD_ASSERT (g != NULL);
  BFD_ASSERT (g != NULL);
 
 
  entry.abfd = abfd;
  entry.abfd = abfd;
  entry.symndx = -1;
  entry.symndx = -1;
  entry.d.h = (struct mips_elf_link_hash_entry *) h;
  entry.d.h = (struct mips_elf_link_hash_entry *) h;
Line 2919... Line 3498...
  entry.gotidx = -1;
  entry.gotidx = -1;
  entry.tls_type = tls_flag;
  entry.tls_type = tls_flag;
 
 
  memcpy (*loc, &entry, sizeof entry);
  memcpy (*loc, &entry, sizeof entry);
 
 
  if (h->got.offset != MINUS_ONE)
 
    return TRUE;
 
 
 
  if (tls_flag == 0)
  if (tls_flag == 0)
    {
    hmips->global_got_area = GGA_NORMAL;
      /* 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
 
         generic ELF copy_indirect_symbol tests for <= 0.  */
 
      h->got.offset = 1;
 
      if (h->forced_local)
 
        g->local_gotno++;
 
    }
 
 
 
  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
mips_elf_record_local_got_symbol (bfd *abfd, long symndx, bfd_vma addend,
mips_elf_record_local_got_symbol (bfd *abfd, long symndx, bfd_vma addend,
                                  struct mips_got_info *g,
                                  struct bfd_link_info *info,
                                  unsigned char tls_flag)
                                  unsigned char tls_flag)
{
{
 
  struct mips_elf_link_hash_table *htab;
 
  struct mips_got_info *g;
  struct mips_got_entry entry, **loc;
  struct mips_got_entry entry, **loc;
 
 
 
  htab = mips_elf_hash_table (info);
 
  g = htab->got_info;
 
  BFD_ASSERT (g != NULL);
 
 
  entry.abfd = abfd;
  entry.abfd = abfd;
  entry.symndx = symndx;
  entry.symndx = symndx;
  entry.d.addend = addend;
  entry.d.addend = addend;
  entry.tls_type = tls_flag;
  entry.tls_type = tls_flag;
  loc = (struct mips_got_entry **)
  loc = (struct mips_got_entry **)
Line 3005... Line 3580...
mips_elf_pages_for_range (const struct mips_got_page_range *range)
mips_elf_pages_for_range (const struct mips_got_page_range *range)
{
{
  return (range->max_addend - range->min_addend + 0x1ffff) >> 16;
  return (range->max_addend - range->min_addend + 0x1ffff) >> 16;
}
}
 
 
/* Record that ABFD has a page relocation against symbol SYMNDX and that
/* Record that ABFD has a page relocation against symbol SYMNDX and
   ADDEND is the addend for that relocation.  G is the GOT information.  */
   that ADDEND is the addend for that relocation.
 
 
 
   This function creates an upper bound on the number of GOT slots
 
   required; no attempt is made to combine references to non-overridable
 
   global symbols across multiple input files.  */
 
 
static bfd_boolean
static bfd_boolean
mips_elf_record_got_page_entry (bfd *abfd, long symndx, bfd_signed_vma addend,
mips_elf_record_got_page_entry (struct bfd_link_info *info, bfd *abfd,
                                struct mips_got_info *g)
                                long symndx, bfd_signed_vma addend)
{
{
 
  struct mips_elf_link_hash_table *htab;
 
  struct mips_got_info *g;
  struct mips_got_page_entry lookup, *entry;
  struct mips_got_page_entry lookup, *entry;
  struct mips_got_page_range **range_ptr, *range;
  struct mips_got_page_range **range_ptr, *range;
  bfd_vma old_pages, new_pages;
  bfd_vma old_pages, new_pages;
  void **loc;
  void **loc;
 
 
 
  htab = mips_elf_hash_table (info);
 
  g = htab->got_info;
 
  BFD_ASSERT (g != NULL);
 
 
  /* Find the mips_got_page_entry hash table entry for this symbol.  */
  /* Find the mips_got_page_entry hash table entry for this symbol.  */
  lookup.abfd = abfd;
  lookup.abfd = abfd;
  lookup.symndx = symndx;
  lookup.symndx = symndx;
  loc = htab_find_slot (g->got_page_entries, &lookup, INSERT);
  loc = htab_find_slot (g->got_page_entries, &lookup, INSERT);
  if (loc == NULL)
  if (loc == NULL)
Line 3094... Line 3679...
      g->page_gotno += new_pages - old_pages;
      g->page_gotno += new_pages - old_pages;
    }
    }
 
 
  return TRUE;
  return TRUE;
}
}
 
 
 
/* Add room for N relocations to the .rel(a).dyn section in ABFD.  */
 
 
 
static void
 
mips_elf_allocate_dynamic_relocations (bfd *abfd, struct bfd_link_info *info,
 
                                       unsigned int n)
 
{
 
  asection *s;
 
  struct mips_elf_link_hash_table *htab;
 
 
 
  htab = mips_elf_hash_table (info);
 
  s = mips_elf_rel_dyn_section (info, FALSE);
 
  BFD_ASSERT (s != NULL);
 
 
 
  if (htab->is_vxworks)
 
    s->size += n * MIPS_ELF_RELA_SIZE (abfd);
 
  else
 
    {
 
      if (s->size == 0)
 
        {
 
          /* Make room for a null element.  */
 
          s->size += MIPS_ELF_REL_SIZE (abfd);
 
          ++s->reloc_count;
 
        }
 
      s->size += n * MIPS_ELF_REL_SIZE (abfd);
 
    }
 
}
 

 
/* A htab_traverse callback for GOT entries.  Set boolean *DATA to true
 
   if the GOT entry is for an indirect or warning symbol.  */
 
 
 
static int
 
mips_elf_check_recreate_got (void **entryp, void *data)
 
{
 
  struct mips_got_entry *entry;
 
  bfd_boolean *must_recreate;
 
 
 
  entry = (struct mips_got_entry *) *entryp;
 
  must_recreate = (bfd_boolean *) data;
 
  if (entry->abfd != NULL && entry->symndx == -1)
 
    {
 
      struct mips_elf_link_hash_entry *h;
 
 
 
      h = entry->d.h;
 
      if (h->root.root.type == bfd_link_hash_indirect
 
          || h->root.root.type == bfd_link_hash_warning)
 
        {
 
          *must_recreate = TRUE;
 
          return 0;
 
        }
 
    }
 
  return 1;
 
}
 
 
 
/* A htab_traverse callback for GOT entries.  Add all entries to
 
   hash table *DATA, converting entries for indirect and warning
 
   symbols into entries for the target symbol.  Set *DATA to null
 
   on error.  */
 
 
 
static int
 
mips_elf_recreate_got (void **entryp, void *data)
 
{
 
  htab_t *new_got;
 
  struct mips_got_entry *entry;
 
  void **slot;
 
 
 
  new_got = (htab_t *) data;
 
  entry = (struct mips_got_entry *) *entryp;
 
  if (entry->abfd != NULL && entry->symndx == -1)
 
    {
 
      struct mips_elf_link_hash_entry *h;
 
 
 
      h = entry->d.h;
 
      while (h->root.root.type == bfd_link_hash_indirect
 
             || h->root.root.type == bfd_link_hash_warning)
 
        {
 
          BFD_ASSERT (h->global_got_area == GGA_NONE);
 
          h = (struct mips_elf_link_hash_entry *) h->root.root.u.i.link;
 
        }
 
      entry->d.h = h;
 
    }
 
  slot = htab_find_slot (*new_got, entry, INSERT);
 
  if (slot == NULL)
 
    {
 
      *new_got = NULL;
 
      return 0;
 
    }
 
  if (*slot == NULL)
 
    *slot = entry;
 
  else
 
    free (entry);
 
  return 1;
 
}
 
 
 
/* If any entries in G->got_entries are for indirect or warning symbols,
 
   replace them with entries for the target symbol.  */
 
 
 
static bfd_boolean
 
mips_elf_resolve_final_got_entries (struct mips_got_info *g)
 
{
 
  bfd_boolean must_recreate;
 
  htab_t new_got;
 
 
 
  must_recreate = FALSE;
 
  htab_traverse (g->got_entries, mips_elf_check_recreate_got, &must_recreate);
 
  if (must_recreate)
 
    {
 
      new_got = htab_create (htab_size (g->got_entries),
 
                             mips_elf_got_entry_hash,
 
                             mips_elf_got_entry_eq, NULL);
 
      htab_traverse (g->got_entries, mips_elf_recreate_got, &new_got);
 
      if (new_got == NULL)
 
        return FALSE;
 
 
 
      /* Each entry in g->got_entries has either been copied to new_got
 
         or freed.  Now delete the hash table itself.  */
 
      htab_delete (g->got_entries);
 
      g->got_entries = new_got;
 
    }
 
  return TRUE;
 
}
 
 
 
/* A mips_elf_link_hash_traverse callback for which DATA points
 
   to a mips_got_info.  Count the number of type (3) entries.  */
 
 
 
static int
 
mips_elf_count_got_symbols (struct mips_elf_link_hash_entry *h, void *data)
 
{
 
  struct mips_got_info *g;
 
 
 
  g = (struct mips_got_info *) data;
 
  if (h->global_got_area != GGA_NONE)
 
    {
 
      if (h->root.forced_local || h->root.dynindx == -1)
 
        {
 
          /* We no longer need this entry if it was only used for
 
             relocations; those relocations will be against the
 
             null or section symbol instead of H.  */
 
          if (h->global_got_area != GGA_RELOC_ONLY)
 
            g->local_gotno++;
 
          h->global_got_area = GGA_NONE;
 
        }
 
      else
 
        {
 
          g->global_gotno++;
 
          if (h->global_got_area == GGA_RELOC_ONLY)
 
            g->reloc_only_gotno++;
 
        }
 
    }
 
  return 1;
 
}


/* Compute the hash value of the bfd in a bfd2got hash entry.  */
/* Compute the hash value of the bfd in a bfd2got hash entry.  */
 
 
static hashval_t
static hashval_t
mips_elf_bfd2got_entry_hash (const void *entry_)
mips_elf_bfd2got_entry_hash (const void *entry_)
Line 3169... Line 3905...
      bfdgot->bfd = input_bfd;
      bfdgot->bfd = input_bfd;
      bfdgot->g = g;
      bfdgot->g = g;
 
 
      g->global_gotsym = NULL;
      g->global_gotsym = NULL;
      g->global_gotno = 0;
      g->global_gotno = 0;
 
      g->reloc_only_gotno = 0;
      g->local_gotno = 0;
      g->local_gotno = 0;
      g->page_gotno = 0;
      g->page_gotno = 0;
      g->assigned_gotno = -1;
      g->assigned_gotno = -1;
      g->tls_gotno = 0;
      g->tls_gotno = 0;
      g->tls_assigned_gotno = 0;
      g->tls_assigned_gotno = 0;
Line 3225... Line 3962...
      if (entry->tls_type & (GOT_TLS_GD | GOT_TLS_LDM))
      if (entry->tls_type & (GOT_TLS_GD | GOT_TLS_LDM))
        g->tls_gotno += 2;
        g->tls_gotno += 2;
      if (entry->tls_type & GOT_TLS_IE)
      if (entry->tls_type & GOT_TLS_IE)
        g->tls_gotno += 1;
        g->tls_gotno += 1;
    }
    }
  else if (entry->symndx >= 0 || entry->d.h->forced_local)
  else if (entry->symndx >= 0 || entry->d.h->root.forced_local)
    ++g->local_gotno;
    ++g->local_gotno;
  else
  else
    ++g->global_gotno;
    ++g->global_gotno;
 
 
  return 1;
  return 1;
Line 3456... Line 4193...
  if (g && entry->tls_type != GOT_NORMAL)
  if (g && entry->tls_type != GOT_NORMAL)
    arg->needed_relocs +=
    arg->needed_relocs +=
      mips_tls_got_relocs (arg->info, entry->tls_type,
      mips_tls_got_relocs (arg->info, entry->tls_type,
                           entry->symndx == -1 ? &entry->d.h->root : NULL);
                           entry->symndx == -1 ? &entry->d.h->root : NULL);
 
 
  if (entry->abfd != NULL && entry->symndx == -1
  if (entry->abfd != NULL
      && entry->d.h->root.dynindx != -1
      && entry->symndx == -1
      && !entry->d.h->forced_local
      && entry->d.h->global_got_area != GGA_NONE)
      && entry->d.h->tls_type == GOT_NORMAL)
 
    {
    {
      if (g)
      if (g)
        {
        {
          BFD_ASSERT (g->global_gotsym == NULL);
          BFD_ASSERT (g->global_gotsym == NULL);
 
 
Line 3473... Line 4209...
                  && entry->d.h->root.def_dynamic
                  && entry->d.h->root.def_dynamic
                  && !entry->d.h->root.def_regular))
                  && !entry->d.h->root.def_regular))
            ++arg->needed_relocs;
            ++arg->needed_relocs;
        }
        }
      else
      else
        entry->d.h->root.got.offset = arg->value;
        entry->d.h->global_got_area = arg->value;
    }
    }
 
 
  return 1;
  return 1;
}
}
 
 
/* Mark any global symbols referenced in the GOT we are iterating over
/* A htab_traverse callback for GOT entries for which DATA is the
   as inelligible for lazy resolution stubs.  */
   bfd_link_info.  Forbid any global symbols from having traditional
 
   lazy-binding stubs.  */
 
 
static int
static int
mips_elf_set_no_stub (void **entryp, void *p ATTRIBUTE_UNUSED)
mips_elf_forbid_lazy_stubs (void **entryp, void *data)
{
{
  struct mips_got_entry *entry = (struct mips_got_entry *)*entryp;
  struct bfd_link_info *info;
 
  struct mips_elf_link_hash_table *htab;
 
  struct mips_got_entry *entry;
 
 
 
  entry = (struct mips_got_entry *) *entryp;
 
  info = (struct bfd_link_info *) data;
 
  htab = mips_elf_hash_table (info);
  if (entry->abfd != NULL
  if (entry->abfd != NULL
      && entry->symndx == -1
      && entry->symndx == -1
      && entry->d.h->root.dynindx != -1)
      && entry->d.h->needs_lazy_stub)
    entry->d.h->no_fn_stub = TRUE;
 
 
 
  return 1;
 
}
 
 
 
/* Follow indirect and warning hash entries so that each got entry
 
   points to the final symbol definition.  P must point to a pointer
 
   to the hash table we're traversing.  Since this traversal may
 
   modify the hash table, we set this pointer to NULL to indicate
 
   we've made a potentially-destructive change to the hash table, so
 
   the traversal must be restarted.  */
 
static int
 
mips_elf_resolve_final_got_entry (void **entryp, void *p)
 
{
 
  struct mips_got_entry *entry = (struct mips_got_entry *)*entryp;
 
  htab_t got_entries = *(htab_t *)p;
 
 
 
  if (entry->abfd != NULL && entry->symndx == -1)
 
    {
    {
      struct mips_elf_link_hash_entry *h = entry->d.h;
      entry->d.h->needs_lazy_stub = FALSE;
 
      htab->lazy_stub_count--;
      while (h->root.root.type == bfd_link_hash_indirect
 
             || h->root.root.type == bfd_link_hash_warning)
 
        h = (struct mips_elf_link_hash_entry *) h->root.root.u.i.link;
 
 
 
      if (entry->d.h == h)
 
        return 1;
 
 
 
      entry->d.h = h;
 
 
 
      /* If we can't find this entry with the new bfd hash, re-insert
 
         it, and get the traversal restarted.  */
 
      if (! htab_find (got_entries, entry))
 
        {
 
          htab_clear_slot (got_entries, entryp);
 
          entryp = htab_find_slot (got_entries, entry, INSERT);
 
          if (! *entryp)
 
            *entryp = entry;
 
          /* Abort the traversal, since the whole table may have
 
             moved, and leave it up to the parent to restart the
 
             process.  */
 
          *(htab_t *)p = NULL;
 
          return 0;
 
        }
 
      /* We might want to decrement the global_gotno count, but it's
 
         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.  */
 
static void
 
mips_elf_resolve_final_got_entries (struct mips_got_info *g)
 
{
 
  htab_t got_entries;
 
 
 
  do
 
    {
 
      got_entries = g->got_entries;
 
 
 
      htab_traverse (got_entries,
 
                     mips_elf_resolve_final_got_entry,
 
                     &got_entries);
 
    }
 
  while (got_entries == NULL);
 
}
 
 
 
/* Return the offset of an input bfd IBFD's GOT from the beginning of
/* Return the offset of an input bfd IBFD's GOT from the beginning of
   the primary GOT.  */
   the primary GOT.  */
static bfd_vma
static bfd_vma
mips_elf_adjust_gp (bfd *abfd, struct mips_got_info *g, bfd *ibfd)
mips_elf_adjust_gp (bfd *abfd, struct mips_got_info *g, bfd *ibfd)
{
{
Line 3583... Line 4265...
/* Turn a single GOT that is too big for 16-bit addressing into
/* Turn a single GOT that is too big for 16-bit addressing into
   a sequence of GOTs, each one 16-bit addressable.  */
   a sequence of GOTs, each one 16-bit addressable.  */
 
 
static bfd_boolean
static bfd_boolean
mips_elf_multi_got (bfd *abfd, struct bfd_link_info *info,
mips_elf_multi_got (bfd *abfd, struct bfd_link_info *info,
                    struct mips_got_info *g, asection *got,
                    asection *got, bfd_size_type pages)
                    bfd_size_type pages)
 
{
{
 
  struct mips_elf_link_hash_table *htab;
  struct mips_elf_got_per_bfd_arg got_per_bfd_arg;
  struct mips_elf_got_per_bfd_arg got_per_bfd_arg;
  struct mips_elf_set_global_got_offset_arg set_got_offset_arg;
  struct mips_elf_set_global_got_offset_arg set_got_offset_arg;
  struct mips_got_info *gg;
  struct mips_got_info *g, *gg;
  unsigned int assign;
  unsigned int assign, needed_relocs;
 
  bfd *dynobj;
 
 
 
  dynobj = elf_hash_table (info)->dynobj;
 
  htab = mips_elf_hash_table (info);
 
  g = htab->got_info;
  g->bfd2got = htab_try_create (1, mips_elf_bfd2got_entry_hash,
  g->bfd2got = htab_try_create (1, mips_elf_bfd2got_entry_hash,
                                mips_elf_bfd2got_entry_eq, NULL);
                                mips_elf_bfd2got_entry_eq, NULL);
  if (g->bfd2got == NULL)
  if (g->bfd2got == NULL)
    return FALSE;
    return FALSE;
 
 
Line 3616... Line 4302...
 
 
  got_per_bfd_arg.current = NULL;
  got_per_bfd_arg.current = NULL;
  got_per_bfd_arg.primary = NULL;
  got_per_bfd_arg.primary = NULL;
  got_per_bfd_arg.max_count = ((MIPS_ELF_GOT_MAX_SIZE (info)
  got_per_bfd_arg.max_count = ((MIPS_ELF_GOT_MAX_SIZE (info)
                                / MIPS_ELF_GOT_SIZE (abfd))
                                / MIPS_ELF_GOT_SIZE (abfd))
                               - MIPS_RESERVED_GOTNO (info));
                               - htab->reserved_gotno);
  got_per_bfd_arg.max_pages = pages;
  got_per_bfd_arg.max_pages = pages;
  /* The number of globals that will be included in the primary GOT.
  /* The number of globals that will be included in the primary GOT.
     See the calls to mips_elf_set_global_got_offset below for more
     See the calls to mips_elf_set_global_got_offset below for more
     information.  */
     information.  */
  got_per_bfd_arg.global_count = g->global_gotno;
  got_per_bfd_arg.global_count = g->global_gotno;
Line 3640... Line 4326...
      if (g->next == NULL)
      if (g->next == NULL)
        return FALSE;
        return FALSE;
 
 
      g->next->global_gotsym = NULL;
      g->next->global_gotsym = NULL;
      g->next->global_gotno = 0;
      g->next->global_gotno = 0;
 
      g->next->reloc_only_gotno = 0;
      g->next->local_gotno = 0;
      g->next->local_gotno = 0;
      g->next->page_gotno = 0;
      g->next->page_gotno = 0;
      g->next->tls_gotno = 0;
      g->next->tls_gotno = 0;
      g->next->assigned_gotno = 0;
      g->next->assigned_gotno = 0;
      g->next->tls_assigned_gotno = 0;
      g->next->tls_assigned_gotno = 0;
Line 3689... Line 4376...
 
 
    BFD_ASSERT (*bfdgotp == NULL);
    BFD_ASSERT (*bfdgotp == NULL);
    *bfdgotp = bfdgot;
    *bfdgotp = bfdgot;
  }
  }
 
 
  /* The IRIX dynamic linker requires every symbol that is referenced
  /* Every symbol that is referenced in a dynamic relocation must be
     in a dynamic relocation to be present in the primary GOT, so
     present in the primary GOT, so arrange for them to appear after
     arrange for them to appear after those that are actually
     those that are actually referenced.  */
     referenced.
  gg->reloc_only_gotno = gg->global_gotno - g->global_gotno;
 
 
     GNU/Linux could very well do without it, but it would slow down
 
     the dynamic linker, since it would have to resolve every dynamic
 
     symbol referenced in other GOTs more than once, without help from
 
     the cache.  Also, knowing that every external symbol has a GOT
 
     helps speed up the resolution of local symbols too, so GNU/Linux
 
     follows IRIX's practice.
 
 
 
     The number 2 is used by mips_elf_sort_hash_table_f to count
 
     global GOT symbols that are unreferenced in the primary GOT, with
 
     an initial dynamic index computed from gg->assigned_gotno, where
 
     the number of unreferenced global entries in the primary GOT is
 
     preserved.  */
 
  if (1)
 
    {
 
      gg->assigned_gotno = gg->global_gotno - g->global_gotno;
 
      g->global_gotno = gg->global_gotno;
      g->global_gotno = gg->global_gotno;
      set_got_offset_arg.value = 2;
 
    }
 
  else
 
    {
 
      /* This could be used for dynamic linkers that don't optimize
 
         symbol resolution while applying relocations so as to use
 
         primary GOT entries or assuming the symbol is locally-defined.
 
         With this code, we assign lower dynamic indices to global
 
         symbols that are not referenced in the primary GOT, so that
 
         their entries can be omitted.  */
 
      gg->assigned_gotno = 0;
 
      set_got_offset_arg.value = -1;
 
    }
 
 
 
  /* Reorder dynamic symbols as described above (which behavior
 
     depends on the setting of VALUE).  */
 
  set_got_offset_arg.g = NULL;
  set_got_offset_arg.g = NULL;
 
  set_got_offset_arg.value = GGA_RELOC_ONLY;
  htab_traverse (gg->got_entries, mips_elf_set_global_got_offset,
  htab_traverse (gg->got_entries, mips_elf_set_global_got_offset,
                 &set_got_offset_arg);
                 &set_got_offset_arg);
  set_got_offset_arg.value = 1;
  set_got_offset_arg.value = GGA_NORMAL;
  htab_traverse (g->got_entries, mips_elf_set_global_got_offset,
  htab_traverse (g->got_entries, mips_elf_set_global_got_offset,
                 &set_got_offset_arg);
                 &set_got_offset_arg);
  if (! mips_elf_sort_hash_table (info, 1))
 
    return FALSE;
 
 
 
  /* Now go through the GOTs assigning them offset ranges.
  /* Now go through the GOTs assigning them offset ranges.
     [assigned_gotno, local_gotno[ will be set to the range of local
     [assigned_gotno, local_gotno[ will be set to the range of local
     entries in each GOT.  We can then compute the end of a GOT by
     entries in each GOT.  We can then compute the end of a GOT by
     adding local_gotno to global_gotno.  We reverse the list and make
     adding local_gotno to global_gotno.  We reverse the list and make
Line 3758... Line 4413...
 
 
  do
  do
    {
    {
      struct mips_got_info *gn;
      struct mips_got_info *gn;
 
 
      assign += MIPS_RESERVED_GOTNO (info);
      assign += htab->reserved_gotno;
      g->assigned_gotno = assign;
      g->assigned_gotno = assign;
      g->local_gotno += assign;
      g->local_gotno += assign;
      g->local_gotno += (pages < g->page_gotno ? pages : g->page_gotno);
      g->local_gotno += (pages < g->page_gotno ? pages : g->page_gotno);
      assign = g->local_gotno + g->global_gotno + g->tls_gotno;
      assign = g->local_gotno + g->global_gotno + g->tls_gotno;
 
 
Line 3779... Line 4434...
      htab_traverse (g->got_entries, mips_elf_initialize_tls_index, g);
      htab_traverse (g->got_entries, mips_elf_initialize_tls_index, g);
 
 
      /* Move onto the next GOT.  It will be a secondary GOT if nonull.  */
      /* Move onto the next GOT.  It will be a secondary GOT if nonull.  */
      g = gn;
      g = gn;
 
 
      /* Mark global symbols in every non-primary GOT as ineligible for
      /* Forbid global symbols in every non-primary GOT from having
         stubs.  */
         lazy-binding stubs.  */
      if (g)
      if (g)
        htab_traverse (g->got_entries, mips_elf_set_no_stub, NULL);
        htab_traverse (g->got_entries, mips_elf_forbid_lazy_stubs, info);
    }
    }
  while (g);
  while (g);
 
 
  got->size = (gg->next->local_gotno
  got->size = (gg->next->local_gotno
                    + gg->next->global_gotno
                    + gg->next->global_gotno
                    + gg->next->tls_gotno) * MIPS_ELF_GOT_SIZE (abfd);
                    + gg->next->tls_gotno) * MIPS_ELF_GOT_SIZE (abfd);
 
 
 
  needed_relocs = 0;
 
  set_got_offset_arg.value = MIPS_ELF_GOT_SIZE (abfd);
 
  set_got_offset_arg.info = info;
 
  for (g = gg->next; g && g->next != gg; g = g->next)
 
    {
 
      unsigned int save_assign;
 
 
 
      /* Assign offsets to global GOT entries.  */
 
      save_assign = g->assigned_gotno;
 
      g->assigned_gotno = g->local_gotno;
 
      set_got_offset_arg.g = g;
 
      set_got_offset_arg.needed_relocs = 0;
 
      htab_traverse (g->got_entries,
 
                     mips_elf_set_global_got_offset,
 
                     &set_got_offset_arg);
 
      needed_relocs += set_got_offset_arg.needed_relocs;
 
      BFD_ASSERT (g->assigned_gotno - g->local_gotno <= g->global_gotno);
 
 
 
      g->assigned_gotno = save_assign;
 
      if (info->shared)
 
        {
 
          needed_relocs += g->local_gotno - g->assigned_gotno;
 
          BFD_ASSERT (g->assigned_gotno == g->next->local_gotno
 
                      + g->next->global_gotno
 
                      + g->next->tls_gotno
 
                      + htab->reserved_gotno);
 
        }
 
    }
 
 
 
  if (needed_relocs)
 
    mips_elf_allocate_dynamic_relocations (dynobj, info,
 
                                           needed_relocs);
 
 
  return TRUE;
  return TRUE;
}
}
 
 


/* Returns the first relocation of type r_type found, beginning with
/* Returns the first relocation of type r_type found, beginning with
Line 3951... Line 4639...
}
}
 
 
/* Create the .got section to hold the global offset table.  */
/* Create the .got section to hold the global offset table.  */
 
 
static bfd_boolean
static bfd_boolean
mips_elf_create_got_section (bfd *abfd, struct bfd_link_info *info,
mips_elf_create_got_section (bfd *abfd, struct bfd_link_info *info)
                             bfd_boolean maybe_exclude)
 
{
{
  flagword flags;
  flagword flags;
  register asection *s;
  register 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;
Line 3965... Line 4652...
  struct mips_elf_link_hash_table *htab;
  struct mips_elf_link_hash_table *htab;
 
 
  htab = mips_elf_hash_table (info);
  htab = mips_elf_hash_table (info);
 
 
  /* This function may be called more than once.  */
  /* This function may be called more than once.  */
  s = mips_elf_got_section (abfd, TRUE);
  if (htab->sgot)
  if (s)
 
    {
 
      if (! maybe_exclude)
 
        s->flags &= ~SEC_EXCLUDE;
 
      return TRUE;
      return TRUE;
    }
 
 
 
  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_LINKER_CREATED);
 
 
  if (maybe_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;
 
  htab->sgot = s;
 
 
  /* 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;
Line 4011... Line 4691...
  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->reloc_only_gotno = 0;
  g->tls_gotno = 0;
  g->tls_gotno = 0;
  g->local_gotno = MIPS_RESERVED_GOTNO (info);
  g->local_gotno = 0;
  g->page_gotno = 0;
  g->page_gotno = 0;
  g->assigned_gotno = MIPS_RESERVED_GOTNO (info);
  g->assigned_gotno = 0;
  g->bfd2got = NULL;
  g->bfd2got = NULL;
  g->next = NULL;
  g->next = NULL;
  g->tls_ldm_offset = MINUS_ONE;
  g->tls_ldm_offset = MINUS_ONE;
  g->got_entries = htab_try_create (1, mips_elf_got_entry_hash,
  g->got_entries = htab_try_create (1, mips_elf_got_entry_hash,
                                    mips_elf_got_entry_eq, NULL);
                                    mips_elf_got_entry_eq, NULL);
Line 4026... Line 4707...
    return FALSE;
    return FALSE;
  g->got_page_entries = htab_try_create (1, mips_got_page_entry_hash,
  g->got_page_entries = htab_try_create (1, mips_got_page_entry_hash,
                                         mips_got_page_entry_eq, NULL);
                                         mips_got_page_entry_eq, NULL);
  if (g->got_page_entries == NULL)
  if (g->got_page_entries == NULL)
    return FALSE;
    return FALSE;
  mips_elf_section_data (s)->u.got_info = g;
  htab->got_info = g;
  mips_elf_section_data (s)->elf.this_hdr.sh_flags
  mips_elf_section_data (s)->elf.this_hdr.sh_flags
    |= SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL;
    |= SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL;
 
 
  /* VxWorks also needs a .got.plt section.  */
  /* We also need a .got.plt section when generating PLTs.  */
  if (htab->is_vxworks)
 
    {
 
      s = bfd_make_section_with_flags (abfd, ".got.plt",
      s = bfd_make_section_with_flags (abfd, ".got.plt",
                                       SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
                                       SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
                                       | SEC_IN_MEMORY | SEC_LINKER_CREATED);
                                       | SEC_IN_MEMORY | SEC_LINKER_CREATED);
      if (s == NULL || !bfd_set_section_alignment (abfd, s, 4))
  if (s == NULL)
        return FALSE;
        return FALSE;
 
 
      htab->sgotplt = s;
      htab->sgotplt = s;
    }
 
  return TRUE;
  return TRUE;
}
}


/* Return true if H refers to the special VxWorks __GOTT_BASE__ or
/* Return true if H refers to the special VxWorks __GOTT_BASE__ or
   __GOTT_INDEX__ symbols.  These symbols are only special for
   __GOTT_INDEX__ symbols.  These symbols are only special for
Line 4056... Line 4734...
  return (mips_elf_hash_table (info)->is_vxworks
  return (mips_elf_hash_table (info)->is_vxworks
          && info->shared
          && info->shared
          && (strcmp (h->root.root.string, "__GOTT_BASE__") == 0
          && (strcmp (h->root.root.string, "__GOTT_BASE__") == 0
              || strcmp (h->root.root.string, "__GOTT_INDEX__") == 0));
              || strcmp (h->root.root.string, "__GOTT_INDEX__") == 0));
}
}
 
 
 
/* Return TRUE if a relocation of type R_TYPE from INPUT_BFD might
 
   require an la25 stub.  See also mips_elf_local_pic_function_p,
 
   which determines whether the destination function ever requires a
 
   stub.  */
 
 
 
static bfd_boolean
 
mips_elf_relocation_needs_la25_stub (bfd *input_bfd, int r_type)
 
{
 
  /* We specifically ignore branches and jumps from EF_PIC objects,
 
     where the onus is on the compiler or programmer to perform any
 
     necessary initialization of $25.  Sometimes such initialization
 
     is unnecessary; for example, -mno-shared functions do not use
 
     the incoming value of $25, and may therefore be called directly.  */
 
  if (PIC_OBJECT_P (input_bfd))
 
    return FALSE;
 
 
 
  switch (r_type)
 
    {
 
    case R_MIPS_26:
 
    case R_MIPS_PC16:
 
    case R_MIPS16_26:
 
      return TRUE;
 
 
 
    default:
 
      return FALSE;
 
    }
 
}


/* Calculate the value produced by the RELOCATION (which comes from
/* Calculate the value produced by the RELOCATION (which comes from
   the INPUT_BFD).  The ADDEND is the addend to use for this
   the INPUT_BFD).  The ADDEND is the addend to use for this
   RELOCATION; RELOCATION->R_ADDEND is ignored.
   RELOCATION; RELOCATION->R_ADDEND is ignored.
 
 
Line 4088... Line 4794...
  /* The address of the symbol against which the relocation is
  /* The address of the symbol against which the relocation is
     occurring.  */
     occurring.  */
  bfd_vma symbol = 0;
  bfd_vma symbol = 0;
  /* 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;
  /* The place (section offset or address) of the storage unit being
  /* The place (section offset or address) of the storage unit being
     relocated.  */
     relocated.  */
  bfd_vma p;
  bfd_vma p;
  /* 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;
  /* The offset into the global offset table at which the address of
  /* The offset into the global offset table at which the address of
     the relocation entry symbol, adjusted by the addend, resides
     the relocation entry symbol, adjusted by the addend, resides
     during execution.  */
     during execution.  */
  bfd_vma g = MINUS_ONE;
  bfd_vma g = MINUS_ONE;
  /* The section in which the symbol referenced by the relocation is
  /* The section in which the symbol referenced by the relocation is
Line 4171... Line 4877...
          addend -= symbol;
          addend -= symbol;
          addend += sec->output_section->vma + sec->output_offset;
          addend += sec->output_section->vma + sec->output_offset;
        }
        }
 
 
      /* MIPS16 text labels should be treated as odd.  */
      /* MIPS16 text labels should be treated as odd.  */
      if (sym->st_other == STO_MIPS16)
      if (ELF_ST_IS_MIPS16 (sym->st_other))
        ++symbol;
        ++symbol;
 
 
      /* Record the name of this symbol, for our caller.  */
      /* Record the name of this symbol, for our caller.  */
      *namep = bfd_elf_string_from_elf_section (input_bfd,
      *namep = bfd_elf_string_from_elf_section (input_bfd,
                                                symtab_hdr->sh_link,
                                                symtab_hdr->sh_link,
                                                sym->st_name);
                                                sym->st_name);
      if (*namep == '\0')
      if (*namep == '\0')
        *namep = bfd_section_name (input_bfd, sec);
        *namep = bfd_section_name (input_bfd, sec);
 
 
      target_is_16_bit_code_p = (sym->st_other == STO_MIPS16);
      target_is_16_bit_code_p = ELF_ST_IS_MIPS16 (sym->st_other);
    }
    }
  else
  else
    {
    {
      /* ??? Could we use RELOC_FOR_GLOBAL_SYMBOL here ?  */
      /* ??? Could we use RELOC_FOR_GLOBAL_SYMBOL here ?  */
 
 
Line 4205... Line 4911...
      if (strcmp (*namep, "_gp_disp") == 0
      if (strcmp (*namep, "_gp_disp") == 0
          && ! NEWABI_P (input_bfd))
          && ! NEWABI_P (input_bfd))
        {
        {
          /* Relocations against _gp_disp are permitted only with
          /* Relocations against _gp_disp are permitted only with
             R_MIPS_HI16 and R_MIPS_LO16 relocations.  */
             R_MIPS_HI16 and R_MIPS_LO16 relocations.  */
          if (r_type != R_MIPS_HI16 && r_type != R_MIPS_LO16
          if (!hi16_reloc_p (r_type) && !lo16_reloc_p (r_type))
              && r_type != R_MIPS16_HI16 && r_type != R_MIPS16_LO16)
 
            return bfd_reloc_notsupported;
            return bfd_reloc_notsupported;
 
 
          gp_disp_p = TRUE;
          gp_disp_p = TRUE;
        }
        }
      /* See if this is the special _gp symbol.  Note that such a
      /* See if this is the special _gp symbol.  Note that such a
Line 4277... Line 4982...
                   || ELF_ST_VISIBILITY (h->root.other))))
                   || ELF_ST_VISIBILITY (h->root.other))))
            return bfd_reloc_undefined;
            return bfd_reloc_undefined;
          symbol = 0;
          symbol = 0;
        }
        }
 
 
      target_is_16_bit_code_p = (h->root.other == STO_MIPS16);
      target_is_16_bit_code_p = ELF_ST_IS_MIPS16 (h->root.other);
    }
    }
 
 
  /* If this is a 32- or 64-bit call to a 16-bit function with a stub, we
  /* If this is a reference to a 16-bit function with a stub, we need
     need to redirect the call to the stub, unless we're already *in*
     to redirect the relocation to the stub unless:
     a stub.  */
 
  if (r_type != R_MIPS16_26 && !info->relocatable
     (a) the relocation is for a MIPS16 JAL;
      && ((h != NULL && h->fn_stub != NULL)
 
 
     (b) the relocation is for a MIPS16 PIC call, and there are no
 
         non-MIPS16 uses of the GOT slot; or
 
 
 
     (c) the section allows direct references to MIPS16 functions.  */
 
  if (r_type != R_MIPS16_26
 
      && !info->relocatable
 
      && ((h != NULL
 
           && h->fn_stub != NULL
 
           && (r_type != R_MIPS16_CALL16 || h->need_fn_stub))
          || (local_p
          || (local_p
              && elf_tdata (input_bfd)->local_stubs != NULL
              && elf_tdata (input_bfd)->local_stubs != NULL
              && elf_tdata (input_bfd)->local_stubs[r_symndx] != NULL))
              && elf_tdata (input_bfd)->local_stubs[r_symndx] != NULL))
      && !mips16_stub_section_p (input_bfd, input_section))
      && !section_allows_mips16_refs_p (input_section))
    {
    {
      /* This is a 32- or 64-bit call to a 16-bit function.  We should
      /* This is a 32- or 64-bit call to a 16-bit function.  We should
         have already noticed that we were going to need the
         have already noticed that we were going to need the
         stub.  */
         stub.  */
      if (local_p)
      if (local_p)
Line 4306... Line 5020...
      symbol = sec->output_section->vma + sec->output_offset;
      symbol = sec->output_section->vma + sec->output_offset;
      /* The target is 16-bit, but the stub isn't.  */
      /* The target is 16-bit, but the stub isn't.  */
      target_is_16_bit_code_p = FALSE;
      target_is_16_bit_code_p = FALSE;
    }
    }
  /* If this is a 16-bit call to a 32- or 64-bit function with a stub, we
  /* If this is a 16-bit call to a 32- or 64-bit function with a stub, we
     need to redirect the call to the stub.  */
     need to redirect the call to the stub.  Note that we specifically
 
     exclude R_MIPS16_CALL16 from this behavior; indirect calls should
 
     use an indirect stub instead.  */
  else if (r_type == R_MIPS16_26 && !info->relocatable
  else if (r_type == R_MIPS16_26 && !info->relocatable
           && ((h != NULL && (h->call_stub != NULL || h->call_fp_stub != NULL))
           && ((h != NULL && (h->call_stub != NULL || h->call_fp_stub != NULL))
               || (local_p
               || (local_p
                   && elf_tdata (input_bfd)->local_call_stubs != NULL
                   && elf_tdata (input_bfd)->local_call_stubs != NULL
                   && elf_tdata (input_bfd)->local_call_stubs[r_symndx] != NULL))
                   && elf_tdata (input_bfd)->local_call_stubs[r_symndx] != NULL))
Line 4346... Line 5062...
        }
        }
 
 
      BFD_ASSERT (sec->size > 0);
      BFD_ASSERT (sec->size > 0);
      symbol = sec->output_section->vma + sec->output_offset;
      symbol = sec->output_section->vma + sec->output_offset;
    }
    }
 
  /* If this is a direct call to a PIC function, redirect to the
 
     non-PIC stub.  */
 
  else if (h != NULL && h->la25_stub
 
           && mips_elf_relocation_needs_la25_stub (input_bfd, r_type))
 
    symbol = (h->la25_stub->stub_section->output_section->vma
 
              + h->la25_stub->stub_section->output_offset
 
              + h->la25_stub->offset);
 
 
  /* Calls from 16-bit code to 32-bit code and vice versa require the
  /* Calls from 16-bit code to 32-bit code and vice versa require the
     special jalx instruction.  */
     special jalx instruction.  */
  *require_jalxp = (!info->relocatable
  *require_jalxp = (!info->relocatable
                    && (((r_type == R_MIPS16_26) && !target_is_16_bit_code_p)
                    && (((r_type == R_MIPS16_26) && !target_is_16_bit_code_p)
                        || ((r_type == R_MIPS_26) && target_is_16_bit_code_p)));
                        || ((r_type == R_MIPS_26) && target_is_16_bit_code_p)));
 
 
  local_p = mips_elf_local_relocation_p (input_bfd, relocation,
  local_p = mips_elf_local_relocation_p (input_bfd, relocation,
                                         local_sections, TRUE);
                                         local_sections, TRUE);
 
 
  /* If we haven't already determined the GOT offset, or the GP value,
  gp0 = _bfd_get_gp_value (input_bfd);
     and we're going to need it, get it now.  */
  gp = _bfd_get_gp_value (abfd);
 
  if (htab->got_info)
 
    gp += mips_elf_adjust_gp (abfd, htab->got_info, input_bfd);
 
 
 
  if (gnu_local_gp_p)
 
    symbol = gp;
 
 
 
  /* If we haven't already determined the GOT offset, oand we're going
 
     to need it, get it now.  */
  switch (r_type)
  switch (r_type)
    {
    {
    case R_MIPS_GOT_PAGE:
    case R_MIPS_GOT_PAGE:
    case R_MIPS_GOT_OFST:
    case R_MIPS_GOT_OFST:
      /* We need to decay to GOT_DISP/addend if the symbol doesn't
      /* We need to decay to GOT_DISP/addend if the symbol doesn't
Line 4369... Line 5100...
      local_p = local_p || _bfd_elf_symbol_refs_local_p (&h->root, info, 1);
      local_p = local_p || _bfd_elf_symbol_refs_local_p (&h->root, info, 1);
      if (local_p || r_type == R_MIPS_GOT_OFST)
      if (local_p || r_type == R_MIPS_GOT_OFST)
        break;
        break;
      /* Fall through.  */
      /* Fall through.  */
 
 
 
    case R_MIPS16_CALL16:
 
    case R_MIPS16_GOT16:
    case R_MIPS_CALL16:
    case R_MIPS_CALL16:
    case R_MIPS_GOT16:
    case R_MIPS_GOT16:
    case R_MIPS_GOT_DISP:
    case R_MIPS_GOT_DISP:
    case R_MIPS_GOT_HI16:
    case R_MIPS_GOT_HI16:
    case R_MIPS_CALL_HI16:
    case R_MIPS_CALL_HI16:
Line 4394... Line 5127...
          /* On VxWorks, CALL relocations should refer to the .got.plt
          /* On VxWorks, CALL relocations should refer to the .got.plt
             entry, which is initialized to point at the PLT stub.  */
             entry, which is initialized to point at the PLT stub.  */
          if (htab->is_vxworks
          if (htab->is_vxworks
              && (r_type == R_MIPS_CALL_HI16
              && (r_type == R_MIPS_CALL_HI16
                  || r_type == R_MIPS_CALL_LO16
                  || r_type == R_MIPS_CALL_LO16
                  || r_type == R_MIPS_CALL16))
                  || call16_reloc_p (r_type)))
            {
            {
              BFD_ASSERT (addend == 0);
              BFD_ASSERT (addend == 0);
              BFD_ASSERT (h->root.needs_plt);
              BFD_ASSERT (h->root.needs_plt);
              g = mips_elf_gotplt_index (info, &h->root);
              g = mips_elf_gotplt_index (info, &h->root);
            }
            }
Line 4414... Line 5147...
              if (h->tls_type == GOT_NORMAL
              if (h->tls_type == GOT_NORMAL
                  && (! elf_hash_table(info)->dynamic_sections_created
                  && (! elf_hash_table(info)->dynamic_sections_created
                      || (info->shared
                      || (info->shared
                          && (info->symbolic || h->root.forced_local)
                          && (info->symbolic || h->root.forced_local)
                          && 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.  */
                  asection *sgot = mips_elf_got_section (dynobj, FALSE);
                MIPS_ELF_PUT_WORD (dynobj, symbol, htab->sgot->contents + g);
                  MIPS_ELF_PUT_WORD (dynobj, symbol, sgot->contents + g);
 
                }
 
            }
            }
        }
        }
      else if (!htab->is_vxworks
      else if (!htab->is_vxworks
               && (r_type == R_MIPS_CALL16 || (r_type == R_MIPS_GOT16)))
               && (call16_reloc_p (r_type) || got16_reloc_p (r_type)))
        /* The calculation below does not involve "g".  */
        /* The calculation below does not involve "g".  */
        break;
        break;
      else
      else
        {
        {
          g = mips_elf_local_got_index (abfd, input_bfd, info,
          g = mips_elf_local_got_index (abfd, input_bfd, info,
Line 4436... Line 5166...
          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 = mips_elf_got_offset_from_index (dynobj, abfd, input_bfd, g);
      g = mips_elf_got_offset_from_index (info, abfd, input_bfd, g);
      break;
 
 
 
    case R_MIPS_HI16:
 
    case R_MIPS_LO16:
 
    case R_MIPS_GPREL16:
 
    case R_MIPS_GPREL32:
 
    case R_MIPS_LITERAL:
 
    case R_MIPS16_HI16:
 
    case R_MIPS16_LO16:
 
    case R_MIPS16_GPREL:
 
      gp0 = _bfd_get_gp_value (input_bfd);
 
      gp = _bfd_get_gp_value (abfd);
 
      if (dynobj)
 
        gp += mips_elf_adjust_gp (abfd, mips_elf_got_info (dynobj, NULL),
 
                                  input_bfd);
 
      break;
 
 
 
    default:
 
      break;
      break;
    }
    }
 
 
  if (gnu_local_gp_p)
 
    symbol = gp;
 
 
 
  /* Relocations against the VxWorks __GOTT_BASE__ and __GOTT_INDEX__
  /* Relocations against the VxWorks __GOTT_BASE__ and __GOTT_INDEX__
     symbols are resolved by the loader.  Add them to .rela.dyn.  */
     symbols are resolved by the loader.  Add them to .rela.dyn.  */
  if (h != NULL && is_gott_symbol (info, &h->root))
  if (h != NULL && is_gott_symbol (info, &h->root))
    {
    {
      Elf_Internal_Rela outrel;
      Elf_Internal_Rela outrel;
Line 4504... Line 5213...
 
 
    case R_MIPS_32:
    case R_MIPS_32:
    case R_MIPS_REL32:
    case R_MIPS_REL32:
    case R_MIPS_64:
    case R_MIPS_64:
      if ((info->shared
      if ((info->shared
           || (!htab->is_vxworks
           || (htab->root.dynamic_sections_created
               && htab->root.dynamic_sections_created
 
               && h != NULL
               && h != NULL
               && h->root.def_dynamic
               && h->root.def_dynamic
               && !h->root.def_regular))
               && !h->root.def_regular
 
               && !h->has_static_relocs))
          && r_symndx != 0
          && r_symndx != 0
 
          && (h == NULL
 
              || h->root.root.type != bfd_link_hash_undefweak
 
              || ELF_ST_VISIBILITY (h->root.other) == STV_DEFAULT)
          && (input_section->flags & SEC_ALLOC) != 0)
          && (input_section->flags & SEC_ALLOC) != 0)
        {
        {
          /* If we're creating a shared library, or this relocation is
          /* If we're creating a shared library, then we can't know
             against a symbol in a shared library, then we can't know
 
             where the symbol will end up.  So, we create a relocation
             where the symbol will end up.  So, we create a relocation
             record in the output, and leave the job up to the dynamic
             record in the output, and leave the job up to the dynamic
             linker.
             linker.  We must do the same for executable references to
 
             shared library symbols, unless we've decided to use copy
             In VxWorks executables, references to external symbols
             relocs or PLTs instead.  */
             are handled using copy relocs or PLT stubs, so there's
 
             no need to add a dynamic relocation here.  */
 
          value = addend;
          value = addend;
          if (!mips_elf_create_dynamic_relocation (abfd,
          if (!mips_elf_create_dynamic_relocation (abfd,
                                                   info,
                                                   info,
                                                   relocation,
                                                   relocation,
                                                   h,
                                                   h,
Line 4672... Line 5381...
      if (was_local_p)
      if (was_local_p)
        value += gp0;
        value += gp0;
      overflowed_p = mips_elf_overflow_p (value, 16);
      overflowed_p = mips_elf_overflow_p (value, 16);
      break;
      break;
 
 
 
    case R_MIPS16_GOT16:
 
    case R_MIPS16_CALL16:
    case R_MIPS_GOT16:
    case R_MIPS_GOT16:
    case R_MIPS_CALL16:
    case R_MIPS_CALL16:
      /* VxWorks does not have separate local and global semantics for
      /* VxWorks does not have separate local and global semantics for
         R_MIPS_GOT16; every relocation evaluates to "G".  */
         R_MIPS*_GOT16; every relocation evaluates to "G".  */
      if (!htab->is_vxworks && local_p)
      if (!htab->is_vxworks && local_p)
        {
        {
          bfd_boolean forced;
          bfd_boolean forced;
 
 
          forced = ! mips_elf_local_relocation_p (input_bfd, relocation,
          forced = ! mips_elf_local_relocation_p (input_bfd, relocation,
Line 4687... Line 5398...
          value = mips_elf_got16_entry (abfd, input_bfd, info,
          value = mips_elf_got16_entry (abfd, 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
          value
            = mips_elf_got_offset_from_index (dynobj, abfd, input_bfd, value);
            = mips_elf_got_offset_from_index (info, abfd, input_bfd, value);
          overflowed_p = mips_elf_overflow_p (value, 16);
          overflowed_p = mips_elf_overflow_p (value, 16);
          break;
          break;
        }
        }
 
 
      /* Fall through.  */
      /* Fall through.  */
Line 4741... Line 5452...
      if (! local_p)
      if (! local_p)
        goto got_disp;
        goto got_disp;
      value = mips_elf_got_page (abfd, input_bfd, info, symbol + addend, NULL);
      value = mips_elf_got_page (abfd, input_bfd, info, symbol + addend, NULL);
      if (value == MINUS_ONE)
      if (value == MINUS_ONE)
        return bfd_reloc_outofrange;
        return bfd_reloc_outofrange;
      value = mips_elf_got_offset_from_index (dynobj, abfd, input_bfd, value);
      value = mips_elf_got_offset_from_index (info, abfd, input_bfd, value);
      overflowed_p = mips_elf_overflow_p (value, 16);
      overflowed_p = mips_elf_overflow_p (value, 16);
      break;
      break;
 
 
    case R_MIPS_GOT_OFST:
    case R_MIPS_GOT_OFST:
      if (local_p)
      if (local_p)
Line 4776... Line 5487...
      break;
      break;
 
 
    case R_MIPS_JALR:
    case R_MIPS_JALR:
      /* This relocation is only a hint.  In some cases, we optimize
      /* This relocation is only a hint.  In some cases, we optimize
         it into a bal instruction.  But we don't try to optimize
         it into a bal instruction.  But we don't try to optimize
         branches to the PLT; that will wind up wasting time.  */
         when the symbol does not resolve locally.  */
      if (h != NULL && h->root.plt.offset != (bfd_vma) -1)
      if (h != NULL && !SYMBOL_CALLS_LOCAL (info, &h->root))
        return bfd_reloc_continue;
        return bfd_reloc_continue;
      value = symbol + addend;
      value = symbol + addend;
      break;
      break;
 
 
    case R_MIPS_PJUMP:
    case R_MIPS_PJUMP:
Line 4884... Line 5595...
 
 
      /* Make this the JALX opcode.  */
      /* Make this the JALX opcode.  */
      x = (x & ~(0x3f << 26)) | (jalx_opcode << 26);
      x = (x & ~(0x3f << 26)) | (jalx_opcode << 26);
    }
    }
 
 
  /* On the RM9000, bal is faster than jal, because bal uses branch
  /* Try converting JAL and JALR to BAL, if the target is in range.  */
     prediction hardware.  If we are linking for the RM9000, and we
  if (!info->relocatable
     see jal, and bal fits, use it instead.  Note that this
 
     transformation should be safe for all architectures.  */
 
  if (bfd_get_mach (input_bfd) == bfd_mach_mips9000
 
      && !info->relocatable
 
      && !require_jalx
      && !require_jalx
      && ((r_type == R_MIPS_26 && (x >> 26) == 0x3)         /* jal addr */
      && ((JAL_TO_BAL_P (input_bfd)
          || (r_type == R_MIPS_JALR && x == 0x0320f809)))   /* jalr t9 */
           && r_type == R_MIPS_26
 
           && (x >> 26) == 0x3)         /* jal addr */
 
          || (JALR_TO_BAL_P (input_bfd)
 
              && r_type == R_MIPS_JALR
 
              && x == 0x0320f809)))     /* jalr t9 */
    {
    {
      bfd_vma addr;
      bfd_vma addr;
      bfd_vma dest;
      bfd_vma dest;
      bfd_signed_vma off;
      bfd_signed_vma off;
 
 
Line 4919... Line 5630...
  _bfd_mips16_elf_reloc_shuffle(input_bfd, r_type, !info->relocatable,
  _bfd_mips16_elf_reloc_shuffle(input_bfd, r_type, !info->relocatable,
                                location);
                                location);
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* Returns TRUE if SECTION is a MIPS16 stub section.  */
 
 
 
static bfd_boolean
 
mips16_stub_section_p (bfd *abfd ATTRIBUTE_UNUSED, asection *section)
 
{
 
  const char *name = bfd_get_section_name (abfd, section);
 
 
 
  return FN_STUB_P (name) || CALL_STUB_P (name) || CALL_FP_STUB_P (name);
 
}
 


/* Add room for N relocations to the .rel(a).dyn section in ABFD.  */
 
 
 
static void
 
mips_elf_allocate_dynamic_relocations (bfd *abfd, struct bfd_link_info *info,
 
                                       unsigned int n)
 
{
 
  asection *s;
 
  struct mips_elf_link_hash_table *htab;
 
 
 
  htab = mips_elf_hash_table (info);
 
  s = mips_elf_rel_dyn_section (info, FALSE);
 
  BFD_ASSERT (s != NULL);
 
 
 
  if (htab->is_vxworks)
 
    s->size += n * MIPS_ELF_RELA_SIZE (abfd);
 
  else
 
    {
 
      if (s->size == 0)
 
        {
 
          /* Make room for a null element.  */
 
          s->size += MIPS_ELF_REL_SIZE (abfd);
 
          ++s->reloc_count;
 
        }
 
      s->size += n * MIPS_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.  */
 
 
Line 5228... Line 5902...
      return bfd_mach_mips_loongson_2f;
      return bfd_mach_mips_loongson_2f;
 
 
    case E_MIPS_MACH_OCTEON:
    case E_MIPS_MACH_OCTEON:
      return bfd_mach_mips_octeon;
      return bfd_mach_mips_octeon;
 
 
 
    case E_MIPS_MACH_XLR:
 
      return bfd_mach_mips_xlr;
 
 
    default:
    default:
      switch (flags & EF_MIPS_ARCH)
      switch (flags & EF_MIPS_ARCH)
        {
        {
        default:
        default:
        case E_MIPS_ARCH_1:
        case E_MIPS_ARCH_1:
Line 5310... Line 5987...
   definition in a shared library.  */
   definition in a shared library.  */
static asection mips_elf_acom_section;
static asection mips_elf_acom_section;
static asymbol mips_elf_acom_symbol;
static asymbol mips_elf_acom_symbol;
static asymbol *mips_elf_acom_symbol_ptr;
static asymbol *mips_elf_acom_symbol_ptr;
 
 
/* Handle the special MIPS section numbers that a symbol may use.
/* This is used for both the 32-bit and the 64-bit ABI.  */
   This is used for both the 32-bit and the 64-bit ABI.  */
 
 
 
void
void
_bfd_mips_elf_symbol_processing (bfd *abfd, asymbol *asym)
_bfd_mips_elf_symbol_processing (bfd *abfd, asymbol *asym)
{
{
  elf_symbol_type *elfsym;
  elf_symbol_type *elfsym;
 
 
 
  /* Handle the special MIPS section numbers that a symbol may use.  */
  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_MIPS_ACOMMON:
    case SHN_MIPS_ACOMMON:
      /* This section is used in a dynamically linked executable file.
      /* This section is used in a dynamically linked executable file.
Line 5405... Line 6082...
            asym->value -= section->vma;
            asym->value -= section->vma;
          }
          }
      }
      }
      break;
      break;
    }
    }
 
 
 
  /* If this is an odd-valued function symbol, assume it's a MIPS16 one.  */
 
  if (ELF_ST_TYPE (elfsym->internal_elf_sym.st_info) == STT_FUNC
 
      && (asym->value & 1) != 0)
 
    {
 
      asym->value--;
 
      elfsym->internal_elf_sym.st_other
 
        = ELF_ST_SET_MIPS16 (elfsym->internal_elf_sym.st_other);
 
    }
}
}


/* Implement elf_backend_eh_frame_address_size.  This differs from
/* Implement elf_backend_eh_frame_address_size.  This differs from
   the default in the way it handles EABI64.
   the default in the way it handles EABI64.
 
 
Line 5586... Line 6272...
 
 
  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);
 
 
 
      /* .sbss is not handled specially here because the GNU/Linux
 
         prelinker can convert .sbss from NOBITS to PROGBITS and
 
         changing it back to NOBITS breaks the binary.  The entry in
 
         _bfd_mips_elf_special_sections will ensure the correct flags
 
         are set on .sbss if BFD creates it without reading it from an
 
         input file, and without special handling here the flags set
 
         on it in an input file will be followed.  */
      if (strcmp (name, ".sdata") == 0
      if (strcmp (name, ".sdata") == 0
          || strcmp (name, ".lit8") == 0
          || strcmp (name, ".lit8") == 0
          || strcmp (name, ".lit4") == 0)
          || strcmp (name, ".lit4") == 0)
        {
        {
          hdr->sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL;
          hdr->sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL;
          hdr->sh_type = SHT_PROGBITS;
          hdr->sh_type = SHT_PROGBITS;
        }
        }
      else if (strcmp (name, ".sbss") == 0)
 
        {
 
          hdr->sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL;
 
          hdr->sh_type = SHT_NOBITS;
 
        }
 
      else if (strcmp (name, ".srdata") == 0)
      else if (strcmp (name, ".srdata") == 0)
        {
        {
          hdr->sh_flags |= SHF_ALLOC | SHF_MIPS_GPREL;
          hdr->sh_flags |= SHF_ALLOC | SHF_MIPS_GPREL;
          hdr->sh_type = SHT_PROGBITS;
          hdr->sh_type = SHT_PROGBITS;
        }
        }
Line 5690... Line 6378...
    case SHT_MIPS_OPTIONS:
    case SHT_MIPS_OPTIONS:
      if (!MIPS_ELF_OPTIONS_SECTION_NAME_P (name))
      if (!MIPS_ELF_OPTIONS_SECTION_NAME_P (name))
        return FALSE;
        return FALSE;
      break;
      break;
    case SHT_MIPS_DWARF:
    case SHT_MIPS_DWARF:
      if (! CONST_STRNEQ (name, ".debug_"))
      if (! CONST_STRNEQ (name, ".debug_")
 
          && ! CONST_STRNEQ (name, ".zdebug_"))
        return FALSE;
        return FALSE;
      break;
      break;
    case SHT_MIPS_SYMBOL_LIB:
    case SHT_MIPS_SYMBOL_LIB:
      if (strcmp (name, ".MIPS.symlib") != 0)
      if (strcmp (name, ".MIPS.symlib") != 0)
        return FALSE;
        return FALSE;
Line 5884... Line 6573...
    {
    {
      hdr->sh_type = SHT_MIPS_OPTIONS;
      hdr->sh_type = SHT_MIPS_OPTIONS;
      hdr->sh_entsize = 1;
      hdr->sh_entsize = 1;
      hdr->sh_flags |= SHF_MIPS_NOSTRIP;
      hdr->sh_flags |= SHF_MIPS_NOSTRIP;
    }
    }
  else if (CONST_STRNEQ (name, ".debug_"))
  else if (CONST_STRNEQ (name, ".debug_")
 
           || CONST_STRNEQ (name, ".zdebug_"))
    {
    {
      hdr->sh_type = SHT_MIPS_DWARF;
      hdr->sh_type = SHT_MIPS_DWARF;
 
 
      /* Irix facilities such as libexc expect a single .debug_frame
      /* Irix facilities such as libexc expect a single .debug_frame
         per executable, the system ones have NOSTRIP set and the linker
         per executable, the system ones have NOSTRIP set and the linker
Line 6108... Line 6798...
    }
    }
 
 
  /* If this is a mips16 text symbol, add 1 to the value to make it
  /* If this is a mips16 text symbol, add 1 to the value to make it
     odd.  This will cause something like .word SYM to come up with
     odd.  This will cause something like .word SYM to come up with
     the right value when it is loaded into the PC.  */
     the right value when it is loaded into the PC.  */
  if (sym->st_other == STO_MIPS16)
  if (ELF_ST_IS_MIPS16 (sym->st_other))
    ++*valp;
    ++*valp;
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* This hook function is called before the linker writes out a global
/* This hook function is called before the linker writes out a global
   symbol.  We mark symbols as small common if appropriate.  This is
   symbol.  We mark symbols as small common if appropriate.  This is
   also where we undo the increment of the value for a mips16 symbol.  */
   also where we undo the increment of the value for a mips16 symbol.  */
 
 
bfd_boolean
int
_bfd_mips_elf_link_output_symbol_hook
_bfd_mips_elf_link_output_symbol_hook
  (struct bfd_link_info *info ATTRIBUTE_UNUSED,
  (struct bfd_link_info *info ATTRIBUTE_UNUSED,
   const char *name ATTRIBUTE_UNUSED, Elf_Internal_Sym *sym,
   const char *name ATTRIBUTE_UNUSED, Elf_Internal_Sym *sym,
   asection *input_sec, struct elf_link_hash_entry *h ATTRIBUTE_UNUSED)
   asection *input_sec, struct elf_link_hash_entry *h ATTRIBUTE_UNUSED)
{
{
Line 6131... Line 6821...
     common in the output file.  */
     common in the output file.  */
  if (sym->st_shndx == SHN_COMMON
  if (sym->st_shndx == SHN_COMMON
      && strcmp (input_sec->name, ".scommon") == 0)
      && strcmp (input_sec->name, ".scommon") == 0)
    sym->st_shndx = SHN_MIPS_SCOMMON;
    sym->st_shndx = SHN_MIPS_SCOMMON;
 
 
  if (sym->st_other == STO_MIPS16)
  if (ELF_ST_IS_MIPS16 (sym->st_other))
    sym->st_value &= ~1;
    sym->st_value &= ~1;
 
 
  return TRUE;
  return 1;
}
}


/* Functions for the dynamic linker.  */
/* Functions for the dynamic linker.  */
 
 
/* Create dynamic sections when linking against a dynamic object.  */
/* Create dynamic sections when linking against a dynamic object.  */
Line 6168... Line 6858...
            return FALSE;
            return FALSE;
        }
        }
    }
    }
 
 
  /* We need to create .got section.  */
  /* We need to create .got section.  */
  if (! mips_elf_create_got_section (abfd, info, FALSE))
  if (!mips_elf_create_got_section (abfd, info))
    return FALSE;
    return FALSE;
 
 
  if (! mips_elf_rel_dyn_section (info, TRUE))
  if (! mips_elf_rel_dyn_section (info, TRUE))
    return FALSE;
    return FALSE;
 
 
  /* Create .stub section.  */
  /* Create .stub section.  */
  if (bfd_get_section_by_name (abfd,
 
                               MIPS_ELF_STUB_SECTION_NAME (abfd)) == NULL)
 
    {
 
      s = bfd_make_section_with_flags (abfd,
      s = bfd_make_section_with_flags (abfd,
                                       MIPS_ELF_STUB_SECTION_NAME (abfd),
                                       MIPS_ELF_STUB_SECTION_NAME (abfd),
                                       flags | SEC_CODE);
                                       flags | SEC_CODE);
      if (s == NULL
      if (s == NULL
          || ! bfd_set_section_alignment (abfd, s,
          || ! bfd_set_section_alignment (abfd, s,
                                          MIPS_ELF_LOG_FILE_ALIGN (abfd)))
                                          MIPS_ELF_LOG_FILE_ALIGN (abfd)))
        return FALSE;
        return FALSE;
    }
  htab->sstubs = s;
 
 
  if ((IRIX_COMPAT (abfd) == ict_irix5 || IRIX_COMPAT (abfd) == ict_none)
  if ((IRIX_COMPAT (abfd) == ict_irix5 || IRIX_COMPAT (abfd) == ict_none)
      && !info->shared
      && !info->shared
      && bfd_get_section_by_name (abfd, ".rld_map") == NULL)
      && bfd_get_section_by_name (abfd, ".rld_map") == NULL)
    {
    {
Line 6292... Line 6979...
          if (! bfd_elf_link_record_dynamic_symbol (info, h))
          if (! bfd_elf_link_record_dynamic_symbol (info, h))
            return FALSE;
            return FALSE;
        }
        }
    }
    }
 
 
  if (htab->is_vxworks)
  /* Create the .plt, .rel(a).plt, .dynbss and .rel(a).bss sections.
    {
 
      /* Create the .plt, .rela.plt, .dynbss and .rela.bss sections.
 
         Also create the _PROCEDURE_LINKAGE_TABLE symbol.  */
         Also create the _PROCEDURE_LINKAGE_TABLE symbol.  */
      if (!_bfd_elf_create_dynamic_sections (abfd, info))
      if (!_bfd_elf_create_dynamic_sections (abfd, info))
        return FALSE;
        return FALSE;
 
 
      /* Cache the sections created above.  */
      /* Cache the sections created above.  */
 
  htab->splt = bfd_get_section_by_name (abfd, ".plt");
      htab->sdynbss = bfd_get_section_by_name (abfd, ".dynbss");
      htab->sdynbss = bfd_get_section_by_name (abfd, ".dynbss");
 
  if (htab->is_vxworks)
 
    {
      htab->srelbss = bfd_get_section_by_name (abfd, ".rela.bss");
      htab->srelbss = bfd_get_section_by_name (abfd, ".rela.bss");
      htab->srelplt = bfd_get_section_by_name (abfd, ".rela.plt");
      htab->srelplt = bfd_get_section_by_name (abfd, ".rela.plt");
      htab->splt = bfd_get_section_by_name (abfd, ".plt");
    }
 
  else
 
    htab->srelplt = bfd_get_section_by_name (abfd, ".rel.plt");
      if (!htab->sdynbss
      if (!htab->sdynbss
          || (!htab->srelbss && !info->shared)
      || (htab->is_vxworks && !htab->srelbss && !info->shared)
          || !htab->srelplt
          || !htab->srelplt
          || !htab->splt)
          || !htab->splt)
        abort ();
        abort ();
 
 
 
  if (htab->is_vxworks)
 
    {
      /* Do the usual VxWorks handling.  */
      /* Do the usual VxWorks handling.  */
      if (!elf_vxworks_create_dynamic_sections (abfd, info, &htab->srelplt2))
      if (!elf_vxworks_create_dynamic_sections (abfd, info, &htab->srelplt2))
        return FALSE;
        return FALSE;
 
 
      /* Work out the PLT sizes.  */
      /* Work out the PLT sizes.  */
Line 6330... Line 7022...
            = 4 * ARRAY_SIZE (mips_vxworks_exec_plt0_entry);
            = 4 * ARRAY_SIZE (mips_vxworks_exec_plt0_entry);
          htab->plt_entry_size
          htab->plt_entry_size
            = 4 * ARRAY_SIZE (mips_vxworks_exec_plt_entry);
            = 4 * ARRAY_SIZE (mips_vxworks_exec_plt_entry);
        }
        }
    }
    }
 
  else if (!info->shared)
 
    {
 
      /* All variants of the plt0 entry are the same size.  */
 
      htab->plt_header_size = 4 * ARRAY_SIZE (mips_o32_exec_plt0_entry);
 
      htab->plt_entry_size = 4 * ARRAY_SIZE (mips_exec_plt_entry);
 
    }
 
 
  return TRUE;
  return TRUE;
}
}


/* Return true if relocation REL against section SEC is a REL rather than
/* Return true if relocation REL against section SEC is a REL rather than
Line 6397... Line 7095...
  const Elf_Internal_Rela *lo16_relocation;
  const Elf_Internal_Rela *lo16_relocation;
  reloc_howto_type *lo16_howto;
  reloc_howto_type *lo16_howto;
  bfd_vma l;
  bfd_vma l;
 
 
  r_type = ELF_R_TYPE (abfd, rel->r_info);
  r_type = ELF_R_TYPE (abfd, rel->r_info);
  if (r_type == R_MIPS16_HI16)
  if (mips16_reloc_p (r_type))
    lo16_type = R_MIPS16_LO16;
    lo16_type = R_MIPS16_LO16;
  else
  else
    lo16_type = R_MIPS_LO16;
    lo16_type = R_MIPS_LO16;
 
 
  /* The combined value is the sum of the HI16 addend, left-shifted by
  /* The combined value is the sum of the HI16 addend, left-shifted by
Line 6466... Line 7164...
{
{
  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 mips_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 *sreloc;
  asection *sreloc;
  const struct elf_backend_data *bed;
  const struct elf_backend_data *bed;
  struct mips_elf_link_hash_table *htab;
  struct mips_elf_link_hash_table *htab;
  bfd_byte *contents;
  bfd_byte *contents;
  bfd_vma addend;
  bfd_vma addend;
Line 6487... Line 7183...
  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;
 
 
 
  bed = get_elf_backend_data (abfd);
 
  rel_end = relocs + sec->reloc_count * bed->s->int_rels_per_ext_rel;
 
 
  /* Check for the mips16 stub sections.  */
  /* Check for the mips16 stub sections.  */
 
 
  name = bfd_get_section_name (abfd, sec);
  name = bfd_get_section_name (abfd, sec);
  if (FN_STUB_P (name))
  if (FN_STUB_P (name))
    {
    {
      unsigned long r_symndx;
      unsigned long r_symndx;
 
 
      /* Look at the relocation information to figure out which symbol
      /* Look at the relocation information to figure out which symbol
         this is for.  */
         this is for.  */
 
 
      r_symndx = ELF_R_SYM (abfd, relocs->r_info);
      r_symndx = mips16_stub_symndx (sec, relocs, rel_end);
 
      if (r_symndx == 0)
 
        {
 
          (*_bfd_error_handler)
 
            (_("%B: Warning: cannot determine the target function for"
 
               " stub section `%s'"),
 
             abfd, name);
 
          bfd_set_error (bfd_error_bad_value);
 
          return FALSE;
 
        }
 
 
      if (r_symndx < extsymoff
      if (r_symndx < extsymoff
          || sym_hashes[r_symndx - extsymoff] == NULL)
          || sym_hashes[r_symndx - extsymoff] == NULL)
        {
        {
          asection *o;
          asection *o;
Line 6515... Line 7223...
              const Elf_Internal_Rela *r, *rend;
              const Elf_Internal_Rela *r, *rend;
 
 
              /* We can ignore stub sections when looking for relocs.  */
              /* We can ignore stub sections when looking for relocs.  */
              if ((o->flags & SEC_RELOC) == 0
              if ((o->flags & SEC_RELOC) == 0
                  || o->reloc_count == 0
                  || o->reloc_count == 0
                  || mips16_stub_section_p (abfd, o))
                  || section_allows_mips16_refs_p (o))
                continue;
                continue;
 
 
              sec_relocs
              sec_relocs
                = _bfd_elf_link_read_relocs (abfd, o, NULL, NULL,
                = _bfd_elf_link_read_relocs (abfd, o, NULL, NULL,
                                             info->keep_memory);
                                             info->keep_memory);
Line 6527... Line 7235...
                return FALSE;
                return FALSE;
 
 
              rend = sec_relocs + o->reloc_count;
              rend = sec_relocs + o->reloc_count;
              for (r = sec_relocs; r < rend; r++)
              for (r = sec_relocs; r < rend; r++)
                if (ELF_R_SYM (abfd, r->r_info) == r_symndx
                if (ELF_R_SYM (abfd, r->r_info) == r_symndx
                    && ELF_R_TYPE (abfd, r->r_info) != R_MIPS16_26)
                    && !mips16_call_reloc_p (ELF_R_TYPE (abfd, r->r_info)))
                  break;
                  break;
 
 
              if (elf_section_data (o)->relocs != sec_relocs)
              if (elf_section_data (o)->relocs != sec_relocs)
                free (sec_relocs);
                free (sec_relocs);
 
 
Line 6613... Line 7321...
      asection **loc;
      asection **loc;
 
 
      /* Look at the relocation information to figure out which symbol
      /* Look at the relocation information to figure out which symbol
         this is for.  */
         this is for.  */
 
 
      r_symndx = ELF_R_SYM (abfd, relocs->r_info);
      r_symndx = mips16_stub_symndx (sec, relocs, rel_end);
 
      if (r_symndx == 0)
 
        {
 
          (*_bfd_error_handler)
 
            (_("%B: Warning: cannot determine the target function for"
 
               " stub section `%s'"),
 
             abfd, name);
 
          bfd_set_error (bfd_error_bad_value);
 
          return FALSE;
 
        }
 
 
      if (r_symndx < extsymoff
      if (r_symndx < extsymoff
          || sym_hashes[r_symndx - extsymoff] == NULL)
          || sym_hashes[r_symndx - extsymoff] == NULL)
        {
        {
          asection *o;
          asection *o;
Line 6631... Line 7348...
              const Elf_Internal_Rela *r, *rend;
              const Elf_Internal_Rela *r, *rend;
 
 
              /* We can ignore stub sections when looking for relocs.  */
              /* We can ignore stub sections when looking for relocs.  */
              if ((o->flags & SEC_RELOC) == 0
              if ((o->flags & SEC_RELOC) == 0
                  || o->reloc_count == 0
                  || o->reloc_count == 0
                  || mips16_stub_section_p (abfd, o))
                  || section_allows_mips16_refs_p (o))
                continue;
                continue;
 
 
              sec_relocs
              sec_relocs
                = _bfd_elf_link_read_relocs (abfd, o, NULL, NULL,
                = _bfd_elf_link_read_relocs (abfd, o, NULL, NULL,
                                             info->keep_memory);
                                             info->keep_memory);
Line 6720... Line 7437...
          *loc = sec;
          *loc = sec;
          mips_elf_hash_table (info)->mips16_stubs_seen = TRUE;
          mips_elf_hash_table (info)->mips16_stubs_seen = TRUE;
        }
        }
    }
    }
 
 
  if (dynobj == NULL)
 
    {
 
      sgot = NULL;
 
      g = NULL;
 
    }
 
  else
 
    {
 
      sgot = mips_elf_got_section (dynobj, FALSE);
 
      if (sgot == NULL)
 
        g = NULL;
 
      else
 
        {
 
          BFD_ASSERT (mips_elf_section_data (sgot) != NULL);
 
          g = mips_elf_section_data (sgot)->u.got_info;
 
          BFD_ASSERT (g != NULL);
 
        }
 
    }
 
 
 
  sreloc = NULL;
  sreloc = NULL;
  bed = get_elf_backend_data (abfd);
 
  rel_end = relocs + sec->reloc_count * bed->s->int_rels_per_ext_rel;
 
  contents = NULL;
  contents = NULL;
  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;
 
      bfd_boolean can_make_dynamic_p;
 
 
      r_symndx = ELF_R_SYM (abfd, rel->r_info);
      r_symndx = ELF_R_SYM (abfd, rel->r_info);
      r_type = ELF_R_TYPE (abfd, rel->r_info);
      r_type = ELF_R_TYPE (abfd, rel->r_info);
 
 
      if (r_symndx < extsymoff)
      if (r_symndx < extsymoff)
Line 6764... Line 7462...
          return FALSE;
          return FALSE;
        }
        }
      else
      else
        {
        {
          h = sym_hashes[r_symndx - extsymoff];
          h = sym_hashes[r_symndx - extsymoff];
 
          while (h != NULL
          /* This may be an indirect symbol created because of a version.  */
                 && (h->root.type == bfd_link_hash_indirect
          if (h != NULL)
                     || h->root.type == bfd_link_hash_warning))
            {
 
              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.  */
      /* Set CAN_MAKE_DYNAMIC_P to true if we can convert this
      if (dynobj == NULL || sgot == NULL)
         relocation into a dynamic one.  */
        {
      can_make_dynamic_p = FALSE;
          switch (r_type)
          switch (r_type)
            {
            {
 
        case R_MIPS16_GOT16:
 
        case R_MIPS16_CALL16:
            case R_MIPS_GOT16:
            case R_MIPS_GOT16:
            case R_MIPS_CALL16:
            case R_MIPS_CALL16:
            case R_MIPS_CALL_HI16:
            case R_MIPS_CALL_HI16:
            case R_MIPS_CALL_LO16:
            case R_MIPS_CALL_LO16:
            case R_MIPS_GOT_HI16:
            case R_MIPS_GOT_HI16:
Line 6792... Line 7489...
            case R_MIPS_TLS_GOTTPREL:
            case R_MIPS_TLS_GOTTPREL:
            case R_MIPS_TLS_GD:
            case R_MIPS_TLS_GD:
            case R_MIPS_TLS_LDM:
            case R_MIPS_TLS_LDM:
              if (dynobj == NULL)
              if (dynobj == NULL)
                elf_hash_table (info)->dynobj = dynobj = abfd;
                elf_hash_table (info)->dynobj = dynobj = abfd;
              if (! mips_elf_create_got_section (dynobj, info, FALSE))
          if (!mips_elf_create_got_section (dynobj, info))
                return FALSE;
                return FALSE;
              g = mips_elf_got_info (dynobj, &sgot);
 
              if (htab->is_vxworks && !info->shared)
              if (htab->is_vxworks && !info->shared)
                {
                {
                  (*_bfd_error_handler)
                  (*_bfd_error_handler)
                    (_("%B: GOT reloc at 0x%lx not expected in executables"),
                    (_("%B: GOT reloc at 0x%lx not expected in executables"),
                     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;
                }
                }
              break;
              break;
 
 
 
          /* This is just a hint; it can safely be ignored.  Don't set
 
             has_static_relocs for the corresponding symbol.  */
 
        case R_MIPS_JALR:
 
          break;
 
 
            case R_MIPS_32:
            case R_MIPS_32:
            case R_MIPS_REL32:
            case R_MIPS_REL32:
            case R_MIPS_64:
            case R_MIPS_64:
              /* In VxWorks executables, references to external symbols
              /* In VxWorks executables, references to external symbols
                 are handled using copy relocs or PLT stubs, so there's
             must be handled using copy relocs or PLT entries; it is not
                 no need to add a dynamic relocation here.  */
             possible to convert this relocation into a dynamic one.
              if (dynobj == NULL
 
                  && (info->shared || (h != NULL && !htab->is_vxworks))
             For executables that use PLTs and copy-relocs, we have a
 
             choice between converting the relocation into a dynamic
 
             one or using copy relocations or PLT entries.  It is
 
             usually better to do the former, unless the relocation is
 
             against a read-only section.  */
 
          if ((info->shared
 
               || (h != NULL
 
                   && !htab->is_vxworks
 
                   && strcmp (h->root.root.string, "__gnu_local_gp") != 0
 
                   && !(!info->nocopyreloc
 
                        && !PIC_OBJECT_P (abfd)
 
                        && MIPS_ELF_READONLY_SECTION (sec))))
                  && (sec->flags & SEC_ALLOC) != 0)
                  && (sec->flags & SEC_ALLOC) != 0)
 
            {
 
              can_make_dynamic_p = TRUE;
 
              if (dynobj == NULL)
                elf_hash_table (info)->dynobj = dynobj = abfd;
                elf_hash_table (info)->dynobj = dynobj = abfd;
              break;
              break;
 
            }
 
          /* Fall through.  */
 
 
            default:
            default:
 
          /* Most static relocations require pointer equality, except
 
             for branches.  */
 
          if (h)
 
            h->pointer_equality_needed = TRUE;
 
          /* Fall through.  */
 
 
 
        case R_MIPS_26:
 
        case R_MIPS_PC16:
 
        case R_MIPS16_26:
 
          if (h)
 
            ((struct mips_elf_link_hash_entry *) h)->has_static_relocs = TRUE;
              break;
              break;
            }
            }
        }
 
 
 
      if (h)
      if (h)
        {
        {
          ((struct mips_elf_link_hash_entry *) h)->is_relocation_target = TRUE;
 
 
 
          /* Relocations against the special VxWorks __GOTT_BASE__ and
          /* Relocations against the special VxWorks __GOTT_BASE__ and
             __GOTT_INDEX__ symbols must be left to the loader.  Allocate
             __GOTT_INDEX__ symbols must be left to the loader.  Allocate
             room for them in .rela.dyn.  */
             room for them in .rela.dyn.  */
          if (is_gott_symbol (info, h))
          if (is_gott_symbol (info, h))
            {
            {
Line 6847... Line 7572...
            }
            }
        }
        }
      else if (r_type == R_MIPS_CALL_LO16
      else if (r_type == R_MIPS_CALL_LO16
               || r_type == R_MIPS_GOT_LO16
               || r_type == R_MIPS_GOT_LO16
               || r_type == R_MIPS_GOT_DISP
               || r_type == R_MIPS_GOT_DISP
               || (r_type == R_MIPS_GOT16 && htab->is_vxworks))
               || (got16_reloc_p (r_type) && htab->is_vxworks))
        {
        {
          /* We may need a local GOT entry for this relocation.  We
          /* We may need a local GOT entry for this relocation.  We
             don't count R_MIPS_GOT_PAGE because we can estimate the
             don't count R_MIPS_GOT_PAGE because we can estimate the
             maximum number of pages needed by looking at the size of
             maximum number of pages needed by looking at the size of
             the segment.  Similar comments apply to R_MIPS_GOT16 and
             the segment.  Similar comments apply to R_MIPS*_GOT16 and
             R_MIPS_CALL16, except on VxWorks, where GOT relocations
             R_MIPS*_CALL16, except on VxWorks, where GOT relocations
             always evaluate to "G".  We don't count R_MIPS_GOT_HI16, or
             always evaluate to "G".  We don't count R_MIPS_GOT_HI16, or
             R_MIPS_CALL_HI16 because these are always followed by an
             R_MIPS_CALL_HI16 because these are always followed by an
             R_MIPS_GOT_LO16 or R_MIPS_CALL_LO16.  */
             R_MIPS_GOT_LO16 or R_MIPS_CALL_LO16.  */
          if (! mips_elf_record_local_got_symbol (abfd, r_symndx,
          if (! mips_elf_record_local_got_symbol (abfd, r_symndx,
                                                  rel->r_addend, g, 0))
                                                 rel->r_addend, info, 0))
            return FALSE;
            return FALSE;
        }
        }
 
 
 
      if (h != NULL && mips_elf_relocation_needs_la25_stub (abfd, r_type))
 
        ((struct mips_elf_link_hash_entry *) h)->has_nonpic_branches = TRUE;
 
 
      switch (r_type)
      switch (r_type)
        {
        {
        case R_MIPS_CALL16:
        case R_MIPS_CALL16:
 
        case R_MIPS16_CALL16:
          if (h == NULL)
          if (h == NULL)
            {
            {
              (*_bfd_error_handler)
              (*_bfd_error_handler)
                (_("%B: CALL16 reloc at 0x%lx not against global symbol"),
                (_("%B: CALL16 reloc at 0x%lx not against global symbol"),
                 abfd, (unsigned long) rel->r_offset);
                 abfd, (unsigned long) rel->r_offset);
Line 6879... Line 7608...
 
 
        case R_MIPS_CALL_HI16:
        case R_MIPS_CALL_HI16:
        case R_MIPS_CALL_LO16:
        case R_MIPS_CALL_LO16:
          if (h != NULL)
          if (h != NULL)
            {
            {
              /* VxWorks call relocations point the function's .got.plt
              /* VxWorks call relocations point at the function's .got.plt
                 entry, which will be allocated by adjust_dynamic_symbol.
                 entry, which will be allocated by adjust_dynamic_symbol.
                 Otherwise, this symbol requires a global GOT entry.  */
                 Otherwise, this symbol requires a global GOT entry.  */
              if ((!htab->is_vxworks || h->forced_local)
              if ((!htab->is_vxworks || h->forced_local)
                  && !mips_elf_record_global_got_symbol (h, abfd, info, g, 0))
                  && !mips_elf_record_global_got_symbol (h, abfd, info, 0))
                return FALSE;
                return FALSE;
 
 
              /* We need a stub, not a plt entry for the undefined
              /* We need a stub, not a plt entry for the undefined
                 function.  But we record it as if it needs plt.  See
                 function.  But we record it as if it needs plt.  See
                 _bfd_elf_adjust_dynamic_symbol.  */
                 _bfd_elf_adjust_dynamic_symbol.  */
Line 6902... Line 7631...
          if (h)
          if (h)
            {
            {
              struct mips_elf_link_hash_entry *hmips =
              struct mips_elf_link_hash_entry *hmips =
                (struct mips_elf_link_hash_entry *) h;
                (struct mips_elf_link_hash_entry *) h;
 
 
              while (hmips->root.root.type == bfd_link_hash_indirect
              /* This symbol is definitely not overridable.  */
                     || hmips->root.root.type == bfd_link_hash_warning)
 
                hmips = (struct mips_elf_link_hash_entry *)
 
                  hmips->root.root.u.i.link;
 
 
 
              if (hmips->root.def_regular
              if (hmips->root.def_regular
                  && ! (info->shared && ! info->symbolic
                  && ! (info->shared && ! info->symbolic
                        && ! hmips->root.forced_local))
                        && ! hmips->root.forced_local))
                h = NULL;
                h = NULL;
            }
            }
          /* Fall through.  */
          /* Fall through.  */
 
 
 
        case R_MIPS16_GOT16:
        case R_MIPS_GOT16:
        case R_MIPS_GOT16:
        case R_MIPS_GOT_HI16:
        case R_MIPS_GOT_HI16:
        case R_MIPS_GOT_LO16:
        case R_MIPS_GOT_LO16:
          if (!h)
          if (!h || r_type == R_MIPS_GOT_PAGE)
            {
            {
              /* This relocation needs a page entry in the GOT.  */
              /* This relocation needs (or may need, if h != NULL) a
 
                 page entry in the GOT.  For R_MIPS_GOT_PAGE we do not
 
                 know for sure until we know whether the symbol is
 
                 preemptible.  */
              if (mips_elf_rel_relocation_p (abfd, sec, relocs, rel))
              if (mips_elf_rel_relocation_p (abfd, sec, relocs, rel))
                {
                {
                  if (!mips_elf_get_section_contents (abfd, sec, &contents))
                  if (!mips_elf_get_section_contents (abfd, sec, &contents))
                    return FALSE;
                    return FALSE;
                  howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, r_type, FALSE);
                  howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, r_type, FALSE);
Line 6935... Line 7664...
                  else
                  else
                    addend <<= howto->rightshift;
                    addend <<= howto->rightshift;
                }
                }
              else
              else
                addend = rel->r_addend;
                addend = rel->r_addend;
              if (!mips_elf_record_got_page_entry (abfd, r_symndx, addend, g))
              if (!mips_elf_record_got_page_entry (info, abfd, r_symndx,
 
                                                   addend))
                return FALSE;
                return FALSE;
              break;
              break;
            }
            }
          /* Fall through.  */
          /* Fall through.  */
 
 
        case R_MIPS_GOT_DISP:
        case R_MIPS_GOT_DISP:
          if (h && ! mips_elf_record_global_got_symbol (h, abfd, info, g, 0))
          if (h && !mips_elf_record_global_got_symbol (h, abfd, info, 0))
            return FALSE;
            return FALSE;
          break;
          break;
 
 
        case R_MIPS_TLS_GOTTPREL:
        case R_MIPS_TLS_GOTTPREL:
          if (info->shared)
          if (info->shared)
Line 6974... Line 7704...
              {
              {
                struct mips_elf_link_hash_entry *hmips =
                struct mips_elf_link_hash_entry *hmips =
                  (struct mips_elf_link_hash_entry *) h;
                  (struct mips_elf_link_hash_entry *) h;
                hmips->tls_type |= flag;
                hmips->tls_type |= flag;
 
 
                if (h && ! mips_elf_record_global_got_symbol (h, abfd, info, g, flag))
                if (h && !mips_elf_record_global_got_symbol (h, abfd,
 
                                                             info, flag))
                  return FALSE;
                  return FALSE;
              }
              }
            else
            else
              {
              {
                BFD_ASSERT (flag == GOT_TLS_LDM || r_symndx != 0);
                BFD_ASSERT (flag == GOT_TLS_LDM || r_symndx != 0);
 
 
                if (! mips_elf_record_local_got_symbol (abfd, r_symndx,
                if (! mips_elf_record_local_got_symbol (abfd, r_symndx,
                                                        rel->r_addend, g, flag))
                                                       rel->r_addend,
 
                                                       info, flag))
                  return FALSE;
                  return FALSE;
              }
              }
          }
          }
          break;
          break;
 
 
Line 6994... Line 7726...
        case R_MIPS_REL32:
        case R_MIPS_REL32:
        case R_MIPS_64:
        case R_MIPS_64:
          /* In VxWorks executables, references to external symbols
          /* In VxWorks executables, references to external symbols
             are handled using copy relocs or PLT stubs, so there's
             are handled using copy relocs or PLT stubs, so there's
             no need to add a .rela.dyn entry for this relocation.  */
             no need to add a .rela.dyn entry for this relocation.  */
          if ((info->shared || (h != NULL && !htab->is_vxworks))
          if (can_make_dynamic_p)
              && (sec->flags & SEC_ALLOC) != 0)
 
            {
            {
              if (sreloc == NULL)
              if (sreloc == NULL)
                {
                {
                  sreloc = mips_elf_rel_dyn_section (info, TRUE);
                  sreloc = mips_elf_rel_dyn_section (info, TRUE);
                  if (sreloc == NULL)
                  if (sreloc == NULL)
                    return FALSE;
                    return FALSE;
                }
                }
              if (info->shared)
              if (info->shared && h == NULL)
                {
                {
                  /* When creating a shared object, we must copy these
                  /* When creating a shared object, we must copy these
                     reloc types into the output file as R_MIPS_REL32
                     reloc types into the output file as R_MIPS_REL32
                     relocs.  Make room for this reloc in .rel(a).dyn.  */
                     relocs.  Make room for this reloc in .rel(a).dyn.  */
                  mips_elf_allocate_dynamic_relocations (dynobj, info, 1);
                  mips_elf_allocate_dynamic_relocations (dynobj, info, 1);
Line 7018... Line 7749...
                }
                }
              else
              else
                {
                {
                  struct mips_elf_link_hash_entry *hmips;
                  struct mips_elf_link_hash_entry *hmips;
 
 
                  /* We only need to copy this reloc if the symbol is
                  /* For a shared object, we must copy this relocation
                     defined in a dynamic object.  */
                     unless the symbol turns out to be undefined and
 
                     weak with non-default visibility, in which case
 
                     it will be left as zero.
 
 
 
                     We could elide R_MIPS_REL32 for locally binding symbols
 
                     in shared libraries, but do not yet do so.
 
 
 
                     For an executable, we only need to copy this
 
                     reloc if the symbol is defined in a dynamic
 
                     object.  */
                  hmips = (struct mips_elf_link_hash_entry *) h;
                  hmips = (struct mips_elf_link_hash_entry *) h;
                  ++hmips->possibly_dynamic_relocs;
                  ++hmips->possibly_dynamic_relocs;
                  if (MIPS_ELF_READONLY_SECTION (sec))
                  if (MIPS_ELF_READONLY_SECTION (sec))
                    /* 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.  */
                    hmips->readonly_reloc = TRUE;
                    hmips->readonly_reloc = TRUE;
                }
                }
 
 
              /* Even though we don't directly need a GOT entry for
 
                 this symbol, a symbol must have a dynamic symbol
 
                 table index greater that DT_MIPS_GOTSYM if there are
 
                 dynamic relocations against it.  This does not apply
 
                 to VxWorks, which does not have the usual coupling
 
                 between global GOT entries and .dynsym entries.  */
 
              if (h != NULL && !htab->is_vxworks)
 
                {
 
                  if (dynobj == NULL)
 
                    elf_hash_table (info)->dynobj = dynobj = abfd;
 
                  if (! mips_elf_create_got_section (dynobj, info, TRUE))
 
                    return FALSE;
 
                  g = mips_elf_got_info (dynobj, &sgot);
 
                  if (! mips_elf_record_global_got_symbol (h, abfd, info, g, 0))
 
                    return FALSE;
 
                }
 
            }
            }
 
 
          if (SGI_COMPAT (abfd))
          if (SGI_COMPAT (abfd))
            mips_elf_hash_table (info)->compact_rel_size +=
            mips_elf_hash_table (info)->compact_rel_size +=
              sizeof (Elf32_External_crinfo);
              sizeof (Elf32_External_crinfo);
          break;
          break;
 
 
        case R_MIPS_PC16:
 
          if (h)
 
            ((struct mips_elf_link_hash_entry *) h)->is_branch_target = TRUE;
 
          break;
 
 
 
        case R_MIPS_26:
        case R_MIPS_26:
          if (h)
 
            ((struct mips_elf_link_hash_entry *) h)->is_branch_target = TRUE;
 
          /* Fall through.  */
 
 
 
        case R_MIPS_GPREL16:
        case R_MIPS_GPREL16:
        case R_MIPS_LITERAL:
        case R_MIPS_LITERAL:
        case R_MIPS_GPREL32:
        case R_MIPS_GPREL32:
          if (SGI_COMPAT (abfd))
          if (SGI_COMPAT (abfd))
            mips_elf_hash_table (info)->compact_rel_size +=
            mips_elf_hash_table (info)->compact_rel_size +=
Line 7099... Line 7813...
        switch (r_type)
        switch (r_type)
          {
          {
          default:
          default:
            ((struct mips_elf_link_hash_entry *) h)->no_fn_stub = TRUE;
            ((struct mips_elf_link_hash_entry *) h)->no_fn_stub = TRUE;
            break;
            break;
 
          case R_MIPS16_CALL16:
          case R_MIPS_CALL16:
          case R_MIPS_CALL16:
          case R_MIPS_CALL_HI16:
          case R_MIPS_CALL_HI16:
          case R_MIPS_CALL_LO16:
          case R_MIPS_CALL_LO16:
          case R_MIPS_JALR:
          case R_MIPS_JALR:
            break;
            break;
          }
          }
 
 
      /* If this reloc is not a 16 bit call, and it has a global
      /* See if this reloc would need to refer to a MIPS16 hard-float stub,
         symbol, then we will need the fn_stub if there is one.
         if there is one.  We only need to handle global symbols here;
         References from a stub section do not count.  */
         we decide whether to keep or delete stubs for local symbols
 
         when processing the stub's relocations.  */
      if (h != NULL
      if (h != NULL
          && r_type != R_MIPS16_26
          && !mips16_call_reloc_p (r_type)
          && !mips16_stub_section_p (abfd, sec))
          && !section_allows_mips16_refs_p (sec))
        {
        {
          struct mips_elf_link_hash_entry *mh;
          struct mips_elf_link_hash_entry *mh;
 
 
          mh = (struct mips_elf_link_hash_entry *) h;
          mh = (struct mips_elf_link_hash_entry *) h;
          mh->need_fn_stub = TRUE;
          mh->need_fn_stub = TRUE;
        }
        }
    }
 
 
 
  return TRUE;
      /* Refuse some position-dependent relocations when creating a
}
         shared library.  Do not refuse R_MIPS_32 / R_MIPS_64; they're

         not PIC, but we can create dynamic relocations and the result
bfd_boolean
         will be fine.  Also do not refuse R_MIPS_LO16, which can be
_bfd_mips_relax_section (bfd *abfd, asection *sec,
         combined with R_MIPS_GOT16.  */
                         struct bfd_link_info *link_info,
      if (info->shared)
                         bfd_boolean *again)
 
{
{
  Elf_Internal_Rela *internal_relocs;
          switch (r_type)
  Elf_Internal_Rela *irel, *irelend;
            {
  Elf_Internal_Shdr *symtab_hdr;
            case R_MIPS16_HI16:
  bfd_byte *contents = NULL;
            case R_MIPS_HI16:
  size_t extsymoff;
            case R_MIPS_HIGHER:
  bfd_boolean changed_contents = FALSE;
            case R_MIPS_HIGHEST:
  bfd_vma sec_start = sec->output_section->vma + sec->output_offset;
              /* Don't refuse a high part relocation if it's against
  Elf_Internal_Sym *isymbuf = NULL;
                 no symbol (e.g. part of a compound relocation).  */
 
              if (r_symndx == 0)
  /* We are not currently changing any sizes, so only one pass.  */
                break;
  *again = FALSE;
 
 
              /* R_MIPS_HI16 against _gp_disp is used for $gp setup,
 
                 and has a special meaning.  */
 
              if (!NEWABI_P (abfd) && h != NULL
 
                  && strcmp (h->root.root.string, "_gp_disp") == 0)
 
                break;
 
 
 
              /* FALLTHROUGH */
 
 
 
            case R_MIPS16_26:
 
            case R_MIPS_26:
 
              howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, r_type, FALSE);
 
              (*_bfd_error_handler)
 
                (_("%B: relocation %s against `%s' can not be used when making a shared object; recompile with -fPIC"),
 
                 abfd, howto->name,
 
                 (h) ? h->root.root.string : "a local symbol");
 
              bfd_set_error (bfd_error_bad_value);
 
              return FALSE;
 
            default:
 
              break;
 
            }
 
        }
 
    }
 
 
 
  return TRUE;
 
}
 

 
bfd_boolean
 
_bfd_mips_relax_section (bfd *abfd, asection *sec,
 
                         struct bfd_link_info *link_info,
 
                         bfd_boolean *again)
 
{
 
  Elf_Internal_Rela *internal_relocs;
 
  Elf_Internal_Rela *irel, *irelend;
 
  Elf_Internal_Shdr *symtab_hdr;
 
  bfd_byte *contents = NULL;
 
  size_t extsymoff;
 
  bfd_boolean changed_contents = FALSE;
 
  bfd_vma sec_start = sec->output_section->vma + sec->output_offset;
 
  Elf_Internal_Sym *isymbuf = NULL;
 
 
 
  /* We are not currently changing any sizes, so only one pass.  */
 
  *again = FALSE;
 
 
  if (link_info->relocatable)
  if (link_info->relocatable)
    return TRUE;
    return TRUE;
 
 
  internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL,
  internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL,
Line 7284... Line 8040...
      && elf_section_data (sec)->this_hdr.contents != contents)
      && elf_section_data (sec)->this_hdr.contents != contents)
    free (contents);
    free (contents);
  return FALSE;
  return FALSE;
}
}


/* Adjust a symbol defined by a dynamic object and referenced by a
/* Allocate space for global sym dynamic relocs.  */
   regular object.  The current definition is in some section of the
 
   dynamic object, but we're not including those sections.  We have to
 
   change the definition to something the rest of the link can
 
   understand.  */
 
 
 
bfd_boolean
static bfd_boolean
_bfd_mips_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
                                     struct elf_link_hash_entry *h)
 
{
{
 
  struct bfd_link_info *info = inf;
  bfd *dynobj;
  bfd *dynobj;
  struct mips_elf_link_hash_entry *hmips;
  struct mips_elf_link_hash_entry *hmips;
  asection *s;
 
  struct mips_elf_link_hash_table *htab;
  struct mips_elf_link_hash_table *htab;
 
 
  htab = mips_elf_hash_table (info);
  htab = mips_elf_hash_table (info);
  dynobj = elf_hash_table (info)->dynobj;
  dynobj = elf_hash_table (info)->dynobj;
 
  hmips = (struct mips_elf_link_hash_entry *) h;
 
 
  /* Make sure we know what is going on here.  */
  /* VxWorks executables are handled elsewhere; we only need to
  BFD_ASSERT (dynobj != NULL
     allocate relocations in shared objects.  */
              && (h->needs_plt
  if (htab->is_vxworks && !info->shared)
                  || h->u.weakdef != NULL
    return TRUE;
                  || (h->def_dynamic
 
                      && h->ref_regular
 
                      && !h->def_regular)));
 
 
 
  /* If this symbol is defined in a dynamic object, we need to copy
  /* Ignore indirect and warning symbols.  All relocations against
     any R_MIPS_32 or R_MIPS_REL32 relocs against it into the output
     such symbols will be redirected to the target symbol.  */
     file.  */
  if (h->root.type == bfd_link_hash_indirect
  hmips = (struct mips_elf_link_hash_entry *) h;
      || h->root.type == bfd_link_hash_warning)
 
    return TRUE;
 
 
 
  /* If this symbol is defined in a dynamic object, or we are creating
 
     a shared library, we will need to copy any R_MIPS_32 or
 
     R_MIPS_REL32 relocs against it into the output file.  */
  if (! info->relocatable
  if (! info->relocatable
      && hmips->possibly_dynamic_relocs != 0
      && hmips->possibly_dynamic_relocs != 0
      && (h->root.type == bfd_link_hash_defweak
      && (h->root.type == bfd_link_hash_defweak
          || !h->def_regular))
          || !h->def_regular
 
          || info->shared))
    {
    {
      mips_elf_allocate_dynamic_relocations
      bfd_boolean do_copy = TRUE;
        (dynobj, info, hmips->possibly_dynamic_relocs);
 
      if (hmips->readonly_reloc)
 
        /* We tell the dynamic linker that there are relocations
 
           against the text segment.  */
 
        info->flags |= DF_TEXTREL;
 
    }
 
 
 
  /* For a function, create a stub, if allowed.  */
      if (h->root.type == bfd_link_hash_undefweak)
  if (! hmips->no_fn_stub
 
      && h->needs_plt)
 
    {
    {
      if (! elf_hash_table (info)->dynamic_sections_created)
          /* Do not copy relocations for undefined weak symbols with
        return TRUE;
             non-default visibility.  */
 
          if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
 
            do_copy = FALSE;
 
 
      /* If this symbol is not defined in a regular file, then set
          /* Make sure undefined weak symbols are output as a dynamic
         the symbol to the stub location.  This is required to make
             symbol in PIEs.  */
         function pointers compare as equal between the normal
          else if (h->dynindx == -1 && !h->forced_local)
         executable and the shared library.  */
 
      if (!h->def_regular)
 
        {
        {
          /* We need .stub section.  */
              if (! bfd_elf_link_record_dynamic_symbol (info, h))
          s = bfd_get_section_by_name (dynobj,
                return FALSE;
                                       MIPS_ELF_STUB_SECTION_NAME (dynobj));
 
          BFD_ASSERT (s != NULL);
 
 
 
          h->root.u.def.section = s;
 
          h->root.u.def.value = s->size;
 
 
 
          /* XXX Write this stub address somewhere.  */
 
          h->plt.offset = s->size;
 
 
 
          /* Make room for this stub code.  */
 
          s->size += htab->function_stub_size;
 
 
 
          /* The last half word of the stub will be filled with the index
 
             of this symbol in .dynsym section.  */
 
          return TRUE;
 
        }
        }
    }
    }
  else if ((h->type == STT_FUNC)
 
           && !h->needs_plt)
 
    {
 
      /* This will set the entry for this symbol in the GOT to 0, and
 
         the dynamic linker will take care of this.  */
 
      h->root.u.def.value = 0;
 
      return TRUE;
 
    }
 
 
 
  /* If this is a weak symbol, and there is a real definition, the
      if (do_copy)
     processor independent code will have arranged for us to see the
 
     real definition first, and we can just use the same value.  */
 
  if (h->u.weakdef != NULL)
 
    {
    {
      BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined
          /* Even though we don't directly need a GOT entry for this symbol,
                  || h->u.weakdef->root.type == bfd_link_hash_defweak);
             a symbol must have a dynamic symbol table index greater that
      h->root.u.def.section = h->u.weakdef->root.u.def.section;
             DT_MIPS_GOTSYM if there are dynamic relocations against it.  */
      h->root.u.def.value = h->u.weakdef->root.u.def.value;
          if (hmips->global_got_area > GGA_RELOC_ONLY)
      return TRUE;
            hmips->global_got_area = GGA_RELOC_ONLY;
    }
 
 
 
  /* This is a reference to a symbol defined by a dynamic object which
          mips_elf_allocate_dynamic_relocations
     is not a function.  */
            (dynobj, info, hmips->possibly_dynamic_relocs);
 
          if (hmips->readonly_reloc)
 
            /* We tell the dynamic linker that there are relocations
 
               against the text segment.  */
 
            info->flags |= DF_TEXTREL;
 
        }
 
    }
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* Likewise, for VxWorks.  */
/* Adjust a symbol defined by a dynamic object and referenced by a
 
   regular object.  The current definition is in some section of the
 
   dynamic object, but we're not including those sections.  We have to
 
   change the definition to something the rest of the link can
 
   understand.  */
 
 
bfd_boolean
bfd_boolean
_bfd_mips_vxworks_adjust_dynamic_symbol (struct bfd_link_info *info,
_bfd_mips_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 mips_elf_link_hash_entry *hmips;
  struct mips_elf_link_hash_entry *hmips;
  struct mips_elf_link_hash_table *htab;
  struct mips_elf_link_hash_table *htab;
Line 7403... Line 8133...
  hmips = (struct mips_elf_link_hash_entry *) h;
  hmips = (struct mips_elf_link_hash_entry *) h;
 
 
  /* 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->needs_copy
 
                  || h->u.weakdef != NULL
                  || h->u.weakdef != NULL
                  || (h->def_dynamic
                  || (h->def_dynamic
                      && h->ref_regular
                      && h->ref_regular
                      && !h->def_regular)));
                      && !h->def_regular)));
 
 
  /* If the symbol is defined by a dynamic object, we need a PLT stub if
  hmips = (struct mips_elf_link_hash_entry *) h;
     either (a) we want to branch to the symbol or (b) we're linking an
 
     executable that needs a canonical function address.  In the latter
 
     case, the canonical address will be the address of the executable's
 
     load stub.  */
 
  if ((hmips->is_branch_target
 
       || (!info->shared
 
           && h->type == STT_FUNC
 
           && hmips->is_relocation_target))
 
      && h->def_dynamic
 
      && h->ref_regular
 
      && !h->def_regular
 
      && !h->forced_local)
 
    h->needs_plt = 1;
 
 
 
  /* Locally-binding symbols do not need a PLT stub; we can refer to
  /* If there are call relocations against an externally-defined symbol,
     the functions directly.  */
     see whether we can create a MIPS lazy-binding stub for it.  We can
  else if (h->needs_plt
     only do this if all references to the function are through call
           && (SYMBOL_CALLS_LOCAL (info, h)
     relocations, and in that case, the traditional lazy-binding stubs
               || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
     are much more efficient than PLT entries.
                   && h->root.type == bfd_link_hash_undefweak)))
 
 
     Traditional stubs are only available on SVR4 psABI-based systems;
 
     VxWorks always uses PLTs instead.  */
 
  if (!htab->is_vxworks && h->needs_plt && !hmips->no_fn_stub)
    {
    {
      h->needs_plt = 0;
      if (! elf_hash_table (info)->dynamic_sections_created)
      return TRUE;
      return TRUE;
 
 
 
      /* If this symbol is not defined in a regular file, then set
 
         the symbol to the stub location.  This is required to make
 
         function pointers compare as equal between the normal
 
         executable and the shared library.  */
 
      if (!h->def_regular)
 
        {
 
          hmips->needs_lazy_stub = TRUE;
 
          htab->lazy_stub_count++;
 
          return TRUE;
 
        }
    }
    }
 
  /* As above, VxWorks requires PLT entries for externally-defined
 
     functions that are only accessed through call relocations.
 
 
  if (h->needs_plt)
     Both VxWorks and non-VxWorks targets also need PLT entries if there
 
     are static-only relocations against an externally-defined function.
 
     This can technically occur for shared libraries if there are
 
     branches to the symbol, although it is unlikely that this will be
 
     used in practice due to the short ranges involved.  It can occur
 
     for any relative or absolute relocation in executables; in that
 
     case, the PLT entry becomes the function's canonical address.  */
 
  else if (((h->needs_plt && !hmips->no_fn_stub)
 
            || (h->type == STT_FUNC && hmips->has_static_relocs))
 
           && htab->use_plts_and_copy_relocs
 
           && !SYMBOL_CALLS_LOCAL (info, h)
 
           && !(ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
 
                && h->root.type == bfd_link_hash_undefweak))
    {
    {
      /* If this is the first symbol to need a PLT entry, allocate room
      /* If this is the first symbol to need a PLT entry, allocate room
         for the header, and for the header's .rela.plt.unloaded entries.  */
         for the header.  */
      if (htab->splt->size == 0)
      if (htab->splt->size == 0)
        {
        {
 
          BFD_ASSERT (htab->sgotplt->size == 0);
 
 
 
          /* If we're using the PLT additions to the psABI, each PLT
 
             entry is 16 bytes and the PLT0 entry is 32 bytes.
 
             Encourage better cache usage by aligning.  We do this
 
             lazily to avoid pessimizing traditional objects.  */
 
          if (!htab->is_vxworks
 
              && !bfd_set_section_alignment (dynobj, htab->splt, 5))
 
            return FALSE;
 
 
 
          /* Make sure that .got.plt is word-aligned.  We do this lazily
 
             for the same reason as above.  */
 
          if (!bfd_set_section_alignment (dynobj, htab->sgotplt,
 
                                          MIPS_ELF_LOG_FILE_ALIGN (dynobj)))
 
            return FALSE;
 
 
          htab->splt->size += htab->plt_header_size;
          htab->splt->size += htab->plt_header_size;
          if (!info->shared)
 
 
          /* On non-VxWorks targets, the first two entries in .got.plt
 
             are reserved.  */
 
          if (!htab->is_vxworks)
 
            htab->sgotplt->size += 2 * MIPS_ELF_GOT_SIZE (dynobj);
 
 
 
          /* On VxWorks, also allocate room for the header's
 
             .rela.plt.unloaded entries.  */
 
          if (htab->is_vxworks && !info->shared)
            htab->srelplt2->size += 2 * sizeof (Elf32_External_Rela);
            htab->srelplt2->size += 2 * sizeof (Elf32_External_Rela);
        }
        }
 
 
      /* Assign the next .plt entry to this symbol.  */
      /* Assign the next .plt entry to this symbol.  */
      h->plt.offset = htab->splt->size;
      h->plt.offset = htab->splt->size;
      htab->splt->size += htab->plt_entry_size;
      htab->splt->size += htab->plt_entry_size;
 
 
      /* If the output file has no definition of the symbol, set the
      /* If the output file has no definition of the symbol, set the
         symbol's value to the address of the stub.  For executables,
         symbol's value to the address of the stub.  */
         point at the PLT load stub rather than the lazy resolution stub;
      if (!info->shared && !h->def_regular)
         this stub will become the canonical function address.  */
 
      if (!h->def_regular)
 
        {
        {
          h->root.u.def.section = htab->splt;
          h->root.u.def.section = htab->splt;
          h->root.u.def.value = h->plt.offset;
          h->root.u.def.value = h->plt.offset;
          if (!info->shared)
          /* For VxWorks, point at the PLT load stub rather than the
 
             lazy resolution stub; this stub will become the canonical
 
             function address.  */
 
          if (htab->is_vxworks)
            h->root.u.def.value += 8;
            h->root.u.def.value += 8;
        }
        }
 
 
      /* Make room for the .got.plt entry and the R_JUMP_SLOT relocation.  */
      /* Make room for the .got.plt entry and the R_MIPS_JUMP_SLOT
      htab->sgotplt->size += 4;
         relocation.  */
      htab->srelplt->size += sizeof (Elf32_External_Rela);
      htab->sgotplt->size += MIPS_ELF_GOT_SIZE (dynobj);
 
      htab->srelplt->size += (htab->is_vxworks
 
                              ? MIPS_ELF_RELA_SIZE (dynobj)
 
                              : MIPS_ELF_REL_SIZE (dynobj));
 
 
      /* Make room for the .rela.plt.unloaded relocations.  */
      /* Make room for the .rela.plt.unloaded relocations.  */
      if (!info->shared)
      if (htab->is_vxworks && !info->shared)
        htab->srelplt2->size += 3 * sizeof (Elf32_External_Rela);
        htab->srelplt2->size += 3 * sizeof (Elf32_External_Rela);
 
 
      return TRUE;
      /* All relocations against this symbol that could have been made
    }
         dynamic will now refer to the PLT entry instead.  */
 
      hmips->possibly_dynamic_relocs = 0;
 
 
  /* If a function symbol is defined by a dynamic object, and we do not
 
     need a PLT stub for it, the symbol's value should be zero.  */
 
  if (h->type == STT_FUNC
 
      && h->def_dynamic
 
      && h->ref_regular
 
      && !h->def_regular)
 
    {
 
      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
Line 7496... Line 8261...
      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
  /* Otherwise, there is nothing further to do for symbols defined
     is not a function.  */
     in regular objects.  */
  if (info->shared)
  if (h->def_regular)
    return TRUE;
    return TRUE;
 
 
 
  /* There's also nothing more to do if we'll convert all relocations
 
     against this symbol into dynamic relocations.  */
 
  if (!hmips->has_static_relocs)
 
    return TRUE;
 
 
 
  /* We're now relying on copy relocations.  Complain if we have
 
     some that we can't convert.  */
 
  if (!htab->use_plts_and_copy_relocs || info->shared)
 
    {
 
      (*_bfd_error_handler) (_("non-dynamic relocations refer to "
 
                               "dynamic symbol %s"),
 
                             h->root.root.string);
 
      bfd_set_error (bfd_error_bad_value);
 
      return FALSE;
 
    }
 
 
  /* We must allocate the symbol in our .dynbss section, which will
  /* We must allocate the symbol in our .dynbss section, which will
     become part of the .bss section of the executable.  There will be
     become part of the .bss section of the executable.  There will be
     an entry for this symbol in the .dynsym section.  The dynamic
     an entry for this symbol in the .dynsym section.  The dynamic
     object will contain position independent code, so all references
     object will contain position independent code, so all references
     from the dynamic object to this symbol will go through the global
     from the dynamic object to this symbol will go through the global
Line 7513... Line 8294...
     both the dynamic object and the regular object will refer to the
     both the dynamic object and the regular object will refer to the
     same memory location for the variable.  */
     same memory location for the variable.  */
 
 
  if ((h->root.u.def.section->flags & SEC_ALLOC) != 0)
  if ((h->root.u.def.section->flags & SEC_ALLOC) != 0)
    {
    {
 
      if (htab->is_vxworks)
      htab->srelbss->size += sizeof (Elf32_External_Rela);
      htab->srelbss->size += sizeof (Elf32_External_Rela);
 
      else
 
        mips_elf_allocate_dynamic_relocations (dynobj, info, 1);
      h->needs_copy = 1;
      h->needs_copy = 1;
    }
    }
 
 
 
  /* All relocations against this symbol that could have been made
 
     dynamic will now refer to the local copy instead.  */
 
  hmips->possibly_dynamic_relocs = 0;
 
 
  return _bfd_elf_adjust_dynamic_copy (h, htab->sdynbss);
  return _bfd_elf_adjust_dynamic_copy (h, htab->sdynbss);
}
}


/* Return the number of dynamic section symbols required by OUTPUT_BFD.
 
   The number might be exact or a worst-case estimate, depending on how
 
   much information is available to elf_backend_omit_section_dynsym at
 
   the current linking stage.  */
 
 
 
static bfd_size_type
 
count_section_dynsyms (bfd *output_bfd, struct bfd_link_info *info)
 
{
 
  bfd_size_type count;
 
 
 
  count = 0;
 
  if (info->shared || elf_hash_table (info)->is_relocatable_executable)
 
    {
 
      asection *p;
 
      const struct elf_backend_data *bed;
 
 
 
      bed = get_elf_backend_data (output_bfd);
 
      for (p = output_bfd->sections; p ; p = p->next)
 
        if ((p->flags & SEC_EXCLUDE) == 0
 
            && (p->flags & SEC_ALLOC) != 0
 
            && !(*bed->elf_backend_omit_section_dynsym) (output_bfd, info, p))
 
          ++count;
 
    }
 
  return count;
 
}
 
 
 
/* 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.  We
   and the input sections have been assigned to output sections.  We
   check for any mips16 stub sections that we can discard.  */
   check for any mips16 stub sections that we can discard.  */
 
 
bfd_boolean
bfd_boolean
_bfd_mips_elf_always_size_sections (bfd *output_bfd,
_bfd_mips_elf_always_size_sections (bfd *output_bfd,
                                    struct bfd_link_info *info)
                                    struct bfd_link_info *info)
{
{
  asection *ri;
  asection *ri;
 
 
  bfd *dynobj;
 
  asection *s;
 
  struct mips_got_info *g;
 
  int i;
 
  bfd_size_type loadable_size = 0;
 
  bfd_size_type page_gotno;
 
  bfd_size_type dynsymcount;
 
  bfd *sub;
 
  struct mips_elf_count_tls_arg count_tls_arg;
 
  struct mips_elf_link_hash_table *htab;
  struct mips_elf_link_hash_table *htab;
 
  struct mips_htab_traverse_info hti;
 
 
  htab = mips_elf_hash_table (info);
  htab = mips_elf_hash_table (info);
 
 
  /* The .reginfo section has a fixed size.  */
  /* The .reginfo section has a fixed size.  */
  ri = bfd_get_section_by_name (output_bfd, ".reginfo");
  ri = bfd_get_section_by_name (output_bfd, ".reginfo");
  if (ri != NULL)
  if (ri != NULL)
    bfd_set_section_size (output_bfd, ri, sizeof (Elf32_External_RegInfo));
    bfd_set_section_size (output_bfd, ri, sizeof (Elf32_External_RegInfo));
 
 
  if (! (info->relocatable
  hti.info = info;
         || ! mips_elf_hash_table (info)->mips16_stubs_seen))
  hti.output_bfd = output_bfd;
 
  hti.error = FALSE;
    mips_elf_link_hash_traverse (mips_elf_hash_table (info),
    mips_elf_link_hash_traverse (mips_elf_hash_table (info),
                                 mips_elf_check_mips16_stubs, NULL);
                               mips_elf_check_symbols, &hti);
 
  if (hti.error)
 
    return FALSE;
 
 
  dynobj = elf_hash_table (info)->dynobj;
 
  if (dynobj == NULL)
 
    /* Relocatable links don't have it.  */
 
    return TRUE;
    return TRUE;
 
}
 
 
  g = mips_elf_got_info (dynobj, &s);
/* If the link uses a GOT, lay it out and work out its size.  */
 
 
 
static bfd_boolean
 
mips_elf_lay_out_got (bfd *output_bfd, struct bfd_link_info *info)
 
{
 
  bfd *dynobj;
 
  asection *s;
 
  struct mips_got_info *g;
 
  bfd_size_type loadable_size = 0;
 
  bfd_size_type page_gotno;
 
  bfd *sub;
 
  struct mips_elf_count_tls_arg count_tls_arg;
 
  struct mips_elf_link_hash_table *htab;
 
 
 
  htab = mips_elf_hash_table (info);
 
  s = htab->sgot;
  if (s == NULL)
  if (s == NULL)
    return TRUE;
    return TRUE;
 
 
 
  dynobj = elf_hash_table (info)->dynobj;
 
  g = htab->got_info;
 
 
 
  /* Allocate room for the reserved entries.  VxWorks always reserves
 
     3 entries; other objects only reserve 2 entries.  */
 
  BFD_ASSERT (g->assigned_gotno == 0);
 
  if (htab->is_vxworks)
 
    htab->reserved_gotno = 3;
 
  else
 
    htab->reserved_gotno = 2;
 
  g->local_gotno += htab->reserved_gotno;
 
  g->assigned_gotno = htab->reserved_gotno;
 
 
 
  /* Replace entries for indirect and warning symbols with entries for
 
     the target symbol.  */
 
  if (!mips_elf_resolve_final_got_entries (g))
 
    return FALSE;
 
 
 
  /* Count the number of GOT symbols.  */
 
  mips_elf_link_hash_traverse (htab, mips_elf_count_got_symbols, g);
 
 
  /* Calculate the total loadable size of the output.  That
  /* Calculate the total loadable size of the output.  That
     will give us the maximum number of GOT_PAGE entries
     will give us the maximum number of GOT_PAGE entries
     required.  */
     required.  */
  for (sub = info->input_bfds; sub; sub = sub->link_next)
  for (sub = info->input_bfds; sub; sub = sub->link_next)
    {
    {
Line 7606... Line 8396...
          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
 
     a dynamic symbol table index of DT_MIPS_GOTSYM or
 
     higher.  Therefore, it make sense to put those symbols
 
     that need GOT entries at the end of the symbol table.  We
 
     do that here.  */
 
  if (! mips_elf_sort_hash_table (info, 1))
 
    return FALSE;
 
 
 
  if (g->global_gotsym != NULL)
 
    i = elf_hash_table (info)->dynsymcount - g->global_gotsym->dynindx;
 
  else
 
    /* If there are no global symbols, or none requiring
 
       relocations, then GLOBAL_GOTSYM will be NULL.  */
 
    i = 0;
 
 
 
  /* Get a worst-case estimate of the number of dynamic symbols needed.
 
     At this point, dynsymcount does not account for section symbols
 
     and count_section_dynsyms may overestimate the number that will
 
     be needed.  */
 
  dynsymcount = (elf_hash_table (info)->dynsymcount
 
                 + count_section_dynsyms (output_bfd, info));
 
 
 
  /* Determine the size of one stub entry.  */
 
  htab->function_stub_size = (dynsymcount > 0x10000
 
                              ? MIPS_FUNCTION_STUB_BIG_SIZE
 
                              : MIPS_FUNCTION_STUB_NORMAL_SIZE);
 
 
 
  /* In the worst case, we'll get one stub per dynamic symbol, plus
 
     one to account for the dummy entry at the end required by IRIX
 
     rld.  */
 
  loadable_size += htab->function_stub_size * (i + 1);
 
 
 
  if (htab->is_vxworks)
  if (htab->is_vxworks)
    /* There's no need to allocate page entries for VxWorks; R_MIPS_GOT16
    /* There's no need to allocate page entries for VxWorks; R_MIPS*_GOT16
       relocations against local symbols evaluate to "G", and the EABI does
       relocations against local symbols evaluate to "G", and the EABI does
       not include R_MIPS_GOT_PAGE.  */
       not include R_MIPS_GOT_PAGE.  */
    page_gotno = 0;
    page_gotno = 0;
  else
  else
    /* Assume there are two loadable segments consisting of contiguous
    /* Assume there are two loadable segments consisting of contiguous
Line 7655... Line 8413...
  if (page_gotno > g->page_gotno)
  if (page_gotno > g->page_gotno)
    page_gotno = g->page_gotno;
    page_gotno = g->page_gotno;
 
 
  g->local_gotno += page_gotno;
  g->local_gotno += page_gotno;
  s->size += g->local_gotno * MIPS_ELF_GOT_SIZE (output_bfd);
  s->size += g->local_gotno * MIPS_ELF_GOT_SIZE (output_bfd);
 
  s->size += g->global_gotno * MIPS_ELF_GOT_SIZE (output_bfd);
  g->global_gotno = i;
 
  s->size += i * MIPS_ELF_GOT_SIZE (output_bfd);
 
 
 
  /* We need to calculate tls_gotno for global symbols at this point
  /* We need to calculate tls_gotno for global symbols at this point
     instead of building it up earlier, to avoid doublecounting
     instead of building it up earlier, to avoid doublecounting
     entries for one global symbol from multiple input files.  */
     entries for one global symbol from multiple input files.  */
  count_tls_arg.info = info;
  count_tls_arg.info = info;
Line 7670... Line 8426...
                          mips_elf_count_global_tls_entries,
                          mips_elf_count_global_tls_entries,
                          &count_tls_arg);
                          &count_tls_arg);
  g->tls_gotno += count_tls_arg.needed;
  g->tls_gotno += count_tls_arg.needed;
  s->size += g->tls_gotno * MIPS_ELF_GOT_SIZE (output_bfd);
  s->size += g->tls_gotno * MIPS_ELF_GOT_SIZE (output_bfd);
 
 
  mips_elf_resolve_final_got_entries (g);
 
 
 
  /* VxWorks does not support multiple GOTs.  It initializes $gp to
  /* VxWorks does not support multiple GOTs.  It initializes $gp to
     __GOTT_BASE__[__GOTT_INDEX__], the value of which is set by the
     __GOTT_BASE__[__GOTT_INDEX__], the value of which is set by the
     dynamic loader.  */
     dynamic loader.  */
  if (!htab->is_vxworks && s->size > MIPS_ELF_GOT_MAX_SIZE (info))
  if (htab->is_vxworks)
 
    {
 
      /* VxWorks executables do not need a GOT.  */
 
      if (info->shared)
 
        {
 
          /* Each VxWorks GOT entry needs an explicit relocation.  */
 
          unsigned int count;
 
 
 
          count = g->global_gotno + g->local_gotno - htab->reserved_gotno;
 
          if (count)
 
            mips_elf_allocate_dynamic_relocations (dynobj, info, count);
 
        }
 
    }
 
  else if (s->size > MIPS_ELF_GOT_MAX_SIZE (info))
    {
    {
      if (! mips_elf_multi_got (output_bfd, info, g, s, page_gotno))
      if (!mips_elf_multi_got (output_bfd, info, s, page_gotno))
        return FALSE;
        return FALSE;
    }
    }
  else
  else
    {
    {
      /* Set up TLS entries for the first GOT.  */
      struct mips_elf_count_tls_arg arg;
 
 
 
      /* Set up TLS entries.  */
      g->tls_assigned_gotno = g->global_gotno + g->local_gotno;
      g->tls_assigned_gotno = g->global_gotno + g->local_gotno;
      htab_traverse (g->got_entries, mips_elf_initialize_tls_index, g);
      htab_traverse (g->got_entries, mips_elf_initialize_tls_index, g);
 
 
 
      /* Allocate room for the TLS relocations.  */
 
      arg.info = info;
 
      arg.needed = 0;
 
      htab_traverse (g->got_entries, mips_elf_count_local_tls_relocs, &arg);
 
      elf_link_hash_traverse (elf_hash_table (info),
 
                              mips_elf_count_global_tls_relocs,
 
                              &arg);
 
      if (arg.needed)
 
        mips_elf_allocate_dynamic_relocations (dynobj, info, arg.needed);
    }
    }
  htab->computed_got_sizes = TRUE;
 
 
 
  return TRUE;
  return TRUE;
}
}
 
 
 
/* Estimate the size of the .MIPS.stubs section.  */
 
 
 
static void
 
mips_elf_estimate_stub_size (bfd *output_bfd, struct bfd_link_info *info)
 
{
 
  struct mips_elf_link_hash_table *htab;
 
  bfd_size_type dynsymcount;
 
 
 
  htab = mips_elf_hash_table (info);
 
  if (htab->lazy_stub_count == 0)
 
    return;
 
 
 
  /* IRIX rld assumes that a function stub isn't at the end of the .text
 
     section, so add a dummy entry to the end.  */
 
  htab->lazy_stub_count++;
 
 
 
  /* Get a worst-case estimate of the number of dynamic symbols needed.
 
     At this point, dynsymcount does not account for section symbols
 
     and count_section_dynsyms may overestimate the number that will
 
     be needed.  */
 
  dynsymcount = (elf_hash_table (info)->dynsymcount
 
                 + count_section_dynsyms (output_bfd, info));
 
 
 
  /* Determine the size of one stub entry.  */
 
  htab->function_stub_size = (dynsymcount > 0x10000
 
                              ? MIPS_FUNCTION_STUB_BIG_SIZE
 
                              : MIPS_FUNCTION_STUB_NORMAL_SIZE);
 
 
 
  htab->sstubs->size = htab->lazy_stub_count * htab->function_stub_size;
 
}
 
 
 
/* A mips_elf_link_hash_traverse callback for which DATA points to the
 
   MIPS hash table.  If H needs a traditional MIPS lazy-binding stub,
 
   allocate an entry in the stubs section.  */
 
 
 
static bfd_boolean
 
mips_elf_allocate_lazy_stub (struct mips_elf_link_hash_entry *h, void **data)
 
{
 
  struct mips_elf_link_hash_table *htab;
 
 
 
  htab = (struct mips_elf_link_hash_table *) data;
 
  if (h->needs_lazy_stub)
 
    {
 
      h->root.root.u.def.section = htab->sstubs;
 
      h->root.root.u.def.value = htab->sstubs->size;
 
      h->root.plt.offset = htab->sstubs->size;
 
      htab->sstubs->size += htab->function_stub_size;
 
    }
 
  return TRUE;
 
}
 
 
 
/* Allocate offsets in the stubs section to each symbol that needs one.
 
   Set the final size of the .MIPS.stub section.  */
 
 
 
static void
 
mips_elf_lay_out_lazy_stubs (struct bfd_link_info *info)
 
{
 
  struct mips_elf_link_hash_table *htab;
 
 
 
  htab = mips_elf_hash_table (info);
 
  if (htab->lazy_stub_count == 0)
 
    return;
 
 
 
  htab->sstubs->size = 0;
 
  mips_elf_link_hash_traverse (mips_elf_hash_table (info),
 
                               mips_elf_allocate_lazy_stub, htab);
 
  htab->sstubs->size += htab->function_stub_size;
 
  BFD_ASSERT (htab->sstubs->size
 
              == htab->lazy_stub_count * htab->function_stub_size);
 
}
 
 
/* Set the sizes of the dynamic sections.  */
/* Set the sizes of the dynamic sections.  */
 
 
bfd_boolean
bfd_boolean
_bfd_mips_elf_size_dynamic_sections (bfd *output_bfd,
_bfd_mips_elf_size_dynamic_sections (bfd *output_bfd,
                                     struct bfd_link_info *info)
                                     struct bfd_link_info *info)
Line 7718... Line 8567...
          s->size
          s->size
            = strlen (ELF_DYNAMIC_INTERPRETER (output_bfd)) + 1;
            = strlen (ELF_DYNAMIC_INTERPRETER (output_bfd)) + 1;
          s->contents
          s->contents
            = (bfd_byte *) ELF_DYNAMIC_INTERPRETER (output_bfd);
            = (bfd_byte *) ELF_DYNAMIC_INTERPRETER (output_bfd);
        }
        }
 
 
 
      /* Create a symbol for the PLT, if we know that we are using it.  */
 
      if (htab->splt && htab->splt->size > 0 && htab->root.hplt == NULL)
 
        {
 
          struct elf_link_hash_entry *h;
 
 
 
          BFD_ASSERT (htab->use_plts_and_copy_relocs);
 
 
 
          h = _bfd_elf_define_linkage_sym (dynobj, info, htab->splt,
 
                                           "_PROCEDURE_LINKAGE_TABLE_");
 
          htab->root.hplt = h;
 
          if (h == NULL)
 
            return FALSE;
 
          h->type = STT_FUNC;
 
        }
    }
    }
 
 
 
  /* Allocate space for global sym dynamic relocs.  */
 
  elf_link_hash_traverse (&htab->root, allocate_dynrelocs, (PTR) info);
 
 
 
  mips_elf_estimate_stub_size (output_bfd, info);
 
 
 
  if (!mips_elf_lay_out_got (output_bfd, info))
 
    return FALSE;
 
 
 
  mips_elf_lay_out_lazy_stubs (info);
 
 
  /* 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;
  sreldyn = NULL;
 
  for (s = dynobj->sections; s != NULL; s = s->next)
  for (s = dynobj->sections; s != NULL; s = s->next)
    {
    {
      const char *name;
      const char *name;
 
 
      /* It's OK to base decisions on the section name, because none
      /* It's OK to base decisions on the section name, because none
Line 7772... Line 8645...
                 relocation's contents, so our sorting would be
                 relocation's contents, so our sorting would be
                 broken, so don't let it run.  */
                 broken, so don't let it run.  */
              info->combreloc = 0;
              info->combreloc = 0;
            }
            }
        }
        }
      else if (htab->is_vxworks && strcmp (name, ".got") == 0)
 
        {
 
          /* Executables do not need a GOT.  */
 
          if (info->shared)
 
            {
 
              /* Allocate relocations for all but the reserved entries.  */
 
              struct mips_got_info *g;
 
              unsigned int count;
 
 
 
              g = mips_elf_got_info (dynobj, NULL);
 
              count = (g->global_gotno
 
                       + g->local_gotno
 
                       - MIPS_RESERVED_GOTNO (info));
 
              mips_elf_allocate_dynamic_relocations (dynobj, info, count);
 
            }
 
        }
 
      else if (!htab->is_vxworks && CONST_STRNEQ (name, ".got"))
 
        {
 
          /* _bfd_mips_elf_always_size_sections() has already done
 
             most of the work, but some symbols may have been mapped
 
             to versions that we must now resolve in the got_entries
 
             hash tables.  */
 
          struct mips_got_info *gg = mips_elf_got_info (dynobj, NULL);
 
          struct mips_got_info *g = gg;
 
          struct mips_elf_set_global_got_offset_arg set_got_offset_arg;
 
          unsigned int needed_relocs = 0;
 
 
 
          if (gg->next)
 
            {
 
              set_got_offset_arg.value = MIPS_ELF_GOT_SIZE (output_bfd);
 
              set_got_offset_arg.info = info;
 
 
 
              /* NOTE 2005-02-03: How can this call, or the next, ever
 
                 find any indirect entries to resolve?  They were all
 
                 resolved in mips_elf_multi_got.  */
 
              mips_elf_resolve_final_got_entries (gg);
 
              for (g = gg->next; g && g->next != gg; g = g->next)
 
                {
 
                  unsigned int save_assign;
 
 
 
                  mips_elf_resolve_final_got_entries (g);
 
 
 
                  /* Assign offsets to global GOT entries.  */
 
                  save_assign = g->assigned_gotno;
 
                  g->assigned_gotno = g->local_gotno;
 
                  set_got_offset_arg.g = g;
 
                  set_got_offset_arg.needed_relocs = 0;
 
                  htab_traverse (g->got_entries,
 
                                 mips_elf_set_global_got_offset,
 
                                 &set_got_offset_arg);
 
                  needed_relocs += set_got_offset_arg.needed_relocs;
 
                  BFD_ASSERT (g->assigned_gotno - g->local_gotno
 
                              <= g->global_gotno);
 
 
 
                  g->assigned_gotno = save_assign;
 
                  if (info->shared)
 
                    {
 
                      needed_relocs += g->local_gotno - g->assigned_gotno;
 
                      BFD_ASSERT (g->assigned_gotno == g->next->local_gotno
 
                                  + g->next->global_gotno
 
                                  + g->next->tls_gotno
 
                                  + MIPS_RESERVED_GOTNO (info));
 
                    }
 
                }
 
            }
 
          else
 
            {
 
              struct mips_elf_count_tls_arg arg;
 
              arg.info = info;
 
              arg.needed = 0;
 
 
 
              htab_traverse (gg->got_entries, mips_elf_count_local_tls_relocs,
 
                             &arg);
 
              elf_link_hash_traverse (elf_hash_table (info),
 
                                      mips_elf_count_global_tls_relocs,
 
                                      &arg);
 
 
 
              needed_relocs += arg.needed;
 
            }
 
 
 
          if (needed_relocs)
 
            mips_elf_allocate_dynamic_relocations (dynobj, info,
 
                                                   needed_relocs);
 
        }
 
      else if (strcmp (name, MIPS_ELF_STUB_SECTION_NAME (output_bfd)) == 0)
 
        {
 
          /* IRIX rld assumes that the function stub isn't at the end
 
             of .text section.  So put a dummy.  XXX  */
 
          s->size += htab->function_stub_size;
 
        }
 
      else if (! info->shared
      else if (! info->shared
               && ! mips_elf_hash_table (info)->use_rld_obj_head
               && ! mips_elf_hash_table (info)->use_rld_obj_head
               && CONST_STRNEQ (name, ".rld_map"))
               && CONST_STRNEQ (name, ".rld_map"))
        {
        {
          /* We add a room for __rld_map.  It will be filled in by the
          /* We add a room for __rld_map.  It will be filled in by the
Line 7873... Line 8656...
          s->size += 4;
          s->size += 4;
        }
        }
      else if (SGI_COMPAT (output_bfd)
      else if (SGI_COMPAT (output_bfd)
               && CONST_STRNEQ (name, ".compact_rel"))
               && CONST_STRNEQ (name, ".compact_rel"))
        s->size += mips_elf_hash_table (info)->compact_rel_size;
        s->size += mips_elf_hash_table (info)->compact_rel_size;
 
      else if (s == htab->splt)
 
        {
 
          /* If the last PLT entry has a branch delay slot, allocate
 
             room for an extra nop to fill the delay slot.  This is
 
             for CPUs without load interlocking.  */
 
          if (! LOAD_INTERLOCKS_P (output_bfd)
 
              && ! htab->is_vxworks && s->size > 0)
 
            s->size += 4;
 
        }
      else if (! CONST_STRNEQ (name, ".init")
      else if (! CONST_STRNEQ (name, ".init")
 
               && s != htab->sgot
               && s != htab->sgotplt
               && s != htab->sgotplt
               && s != htab->splt)
               && s != htab->sstubs
 
               && s != htab->sdynbss)
        {
        {
          /* 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;
        }
        }
 
 
Line 7890... Line 8684...
        }
        }
 
 
      if ((s->flags & SEC_HAS_CONTENTS) == 0)
      if ((s->flags & SEC_HAS_CONTENTS) == 0)
        continue;
        continue;
 
 
      /* Allocate memory for this section last, since we may increase its
 
         size above.  */
 
      if (strcmp (name, MIPS_ELF_REL_DYN_NAME (info)) == 0)
 
        {
 
          sreldyn = s;
 
          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)
      if (s->contents == NULL)
        {
        {
          bfd_set_error (bfd_error_no_memory);
          bfd_set_error (bfd_error_no_memory);
          return FALSE;
          return FALSE;
        }
        }
    }
    }
 
 
  /* Allocate memory for the .rel(a).dyn section.  */
 
  if (sreldyn != NULL)
 
    {
 
      sreldyn->contents = bfd_zalloc (dynobj, sreldyn->size);
 
      if (sreldyn->contents == NULL)
 
        {
 
          bfd_set_error (bfd_error_no_memory);
 
          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 _bfd_mips_elf_finish_dynamic_sections, but we
         values later, in _bfd_mips_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
Line 7958... Line 8733...
        }
        }
 
 
      if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_PLTGOT, 0))
      if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_PLTGOT, 0))
        return FALSE;
        return FALSE;
 
 
 
      sreldyn = mips_elf_rel_dyn_section (info, FALSE);
      if (htab->is_vxworks)
      if (htab->is_vxworks)
        {
        {
          /* VxWorks uses .rela.dyn instead of .rel.dyn.  It does not
          /* VxWorks uses .rela.dyn instead of .rel.dyn.  It does not
             use any of the DT_MIPS_* tags.  */
             use any of the DT_MIPS_* tags.  */
          if (mips_elf_rel_dyn_section (info, FALSE))
          if (sreldyn && sreldyn->size > 0)
            {
 
              if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_RELA, 0))
 
                return FALSE;
 
 
 
              if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_RELASZ, 0))
 
                return FALSE;
 
 
 
              if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_RELAENT, 0))
 
                return FALSE;
 
            }
 
          if (htab->splt->size > 0)
 
            {
            {
              if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_PLTREL, 0))
              if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_RELA, 0))
                return FALSE;
                return FALSE;
 
 
              if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_JMPREL, 0))
              if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_RELASZ, 0))
                return FALSE;
                return FALSE;
 
 
              if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_PLTRELSZ, 0))
              if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_RELAENT, 0))
                return FALSE;
                return FALSE;
            }
            }
        }
        }
      else
      else
        {
        {
          if (mips_elf_rel_dyn_section (info, FALSE))
          if (sreldyn && sreldyn->size > 0)
            {
            {
              if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_REL, 0))
              if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_REL, 0))
                return FALSE;
                return FALSE;
 
 
              if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_RELSZ, 0))
              if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_RELSZ, 0))
Line 8030... Line 8795...
              && (bfd_get_section_by_name
              && (bfd_get_section_by_name
                  (dynobj, MIPS_ELF_OPTIONS_SECTION_NAME (dynobj)))
                  (dynobj, MIPS_ELF_OPTIONS_SECTION_NAME (dynobj)))
              && !MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_OPTIONS, 0))
              && !MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_OPTIONS, 0))
            return FALSE;
            return FALSE;
        }
        }
 
      if (htab->splt->size > 0)
 
        {
 
          if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_PLTREL, 0))
 
            return FALSE;
 
 
 
          if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_JMPREL, 0))
 
            return FALSE;
 
 
 
          if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_PLTRELSZ, 0))
 
            return FALSE;
 
 
 
          if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_PLTGOT, 0))
 
            return FALSE;
 
        }
      if (htab->is_vxworks
      if (htab->is_vxworks
          && !elf_vxworks_add_dynamic_entries (output_bfd, info))
          && !elf_vxworks_add_dynamic_entries (output_bfd, info))
        return FALSE;
        return FALSE;
    }
    }
 
 
Line 8184... Line 8963...
                                         relocs, rel))
                                         relocs, rel))
            {
            {
              rela_relocation_p = FALSE;
              rela_relocation_p = FALSE;
              addend = mips_elf_read_rel_addend (input_bfd, rel,
              addend = mips_elf_read_rel_addend (input_bfd, rel,
                                                 howto, contents);
                                                 howto, contents);
              if (r_type == R_MIPS_HI16
              if (hi16_reloc_p (r_type)
                  || r_type == R_MIPS16_HI16
                  || (got16_reloc_p (r_type)
                  || (r_type == R_MIPS_GOT16
 
                      && mips_elf_local_relocation_p (input_bfd, rel,
                      && mips_elf_local_relocation_p (input_bfd, rel,
                                                      local_sections, FALSE)))
                                                      local_sections, FALSE)))
                {
                {
                  if (!mips_elf_add_lo16_rel_addend (input_bfd, rel, relend,
                  if (!mips_elf_add_lo16_rel_addend (input_bfd, rel, relend,
                                                     contents, &addend))
                                                     contents, &addend))
Line 8225... Line 9003...
            rel->r_offset -= 4;
            rel->r_offset -= 4;
 
 
          if (!rela_relocation_p && rel->r_addend)
          if (!rela_relocation_p && rel->r_addend)
            {
            {
              addend += rel->r_addend;
              addend += rel->r_addend;
              if (r_type == R_MIPS_HI16
              if (hi16_reloc_p (r_type) || got16_reloc_p (r_type))
                  || r_type == R_MIPS_GOT16)
 
                addend = mips_elf_high (addend);
                addend = mips_elf_high (addend);
              else if (r_type == R_MIPS_HIGHER)
              else if (r_type == R_MIPS_HIGHER)
                addend = mips_elf_higher (addend);
                addend = mips_elf_higher (addend);
              else if (r_type == R_MIPS_HIGHEST)
              else if (r_type == R_MIPS_HIGHEST)
                addend = mips_elf_highest (addend);
                addend = mips_elf_highest (addend);
Line 8426... Line 9203...
    }
    }
 
 
  return TRUE;
  return TRUE;
}
}


 
/* A function that iterates over each entry in la25_stubs and fills
 
   in the code for each one.  DATA points to a mips_htab_traverse_info.  */
 
 
 
static int
 
mips_elf_create_la25_stub (void **slot, void *data)
 
{
 
  struct mips_htab_traverse_info *hti;
 
  struct mips_elf_link_hash_table *htab;
 
  struct mips_elf_la25_stub *stub;
 
  asection *s;
 
  bfd_byte *loc;
 
  bfd_vma offset, target, target_high, target_low;
 
 
 
  stub = (struct mips_elf_la25_stub *) *slot;
 
  hti = (struct mips_htab_traverse_info *) data;
 
  htab = mips_elf_hash_table (hti->info);
 
 
 
  /* Create the section contents, if we haven't already.  */
 
  s = stub->stub_section;
 
  loc = s->contents;
 
  if (loc == NULL)
 
    {
 
      loc = bfd_malloc (s->size);
 
      if (loc == NULL)
 
        {
 
          hti->error = TRUE;
 
          return FALSE;
 
        }
 
      s->contents = loc;
 
    }
 
 
 
  /* Work out where in the section this stub should go.  */
 
  offset = stub->offset;
 
 
 
  /* Work out the target address.  */
 
  target = (stub->h->root.root.u.def.section->output_section->vma
 
            + stub->h->root.root.u.def.section->output_offset
 
            + stub->h->root.root.u.def.value);
 
  target_high = ((target + 0x8000) >> 16) & 0xffff;
 
  target_low = (target & 0xffff);
 
 
 
  if (stub->stub_section != htab->strampoline)
 
    {
 
      /* This is a simple LUI/ADIDU stub.  Zero out the beginning
 
         of the section and write the two instructions at the end.  */
 
      memset (loc, 0, offset);
 
      loc += offset;
 
      bfd_put_32 (hti->output_bfd, LA25_LUI (target_high), loc);
 
      bfd_put_32 (hti->output_bfd, LA25_ADDIU (target_low), loc + 4);
 
    }
 
  else
 
    {
 
      /* This is trampoline.  */
 
      loc += offset;
 
      bfd_put_32 (hti->output_bfd, LA25_LUI (target_high), loc);
 
      bfd_put_32 (hti->output_bfd, LA25_J (target), loc + 4);
 
      bfd_put_32 (hti->output_bfd, LA25_ADDIU (target_low), loc + 8);
 
      bfd_put_32 (hti->output_bfd, 0, loc + 12);
 
    }
 
  return TRUE;
 
}
 
 
/* If NAME is one of the special IRIX6 symbols defined by the linker,
/* If NAME is one of the special IRIX6 symbols defined by the linker,
   adjust it appropriately now.  */
   adjust it appropriately now.  */
 
 
static void
static void
mips_elf_irix6_finish_dynamic_symbol (bfd *abfd ATTRIBUTE_UNUSED,
mips_elf_irix6_finish_dynamic_symbol (bfd *abfd ATTRIBUTE_UNUSED,
Line 8491... Line 9330...
  asection *sgot;
  asection *sgot;
  struct mips_got_info *g, *gg;
  struct mips_got_info *g, *gg;
  const char *name;
  const char *name;
  int idx;
  int idx;
  struct mips_elf_link_hash_table *htab;
  struct mips_elf_link_hash_table *htab;
 
  struct mips_elf_link_hash_entry *hmips;
 
 
  htab = mips_elf_hash_table (info);
  htab = mips_elf_hash_table (info);
  dynobj = elf_hash_table (info)->dynobj;
  dynobj = elf_hash_table (info)->dynobj;
 
  hmips = (struct mips_elf_link_hash_entry *) h;
 
 
  if (h->plt.offset != MINUS_ONE)
  BFD_ASSERT (!htab->is_vxworks);
 
 
 
  if (h->plt.offset != MINUS_ONE && hmips->no_fn_stub)
    {
    {
      asection *s;
      /* We've decided to create a PLT entry for this symbol.  */
 
      bfd_byte *loc;
 
      bfd_vma header_address, plt_index, got_address;
 
      bfd_vma got_address_high, got_address_low, load;
 
      const bfd_vma *plt_entry;
 
 
 
      BFD_ASSERT (htab->use_plts_and_copy_relocs);
 
      BFD_ASSERT (h->dynindx != -1);
 
      BFD_ASSERT (htab->splt != NULL);
 
      BFD_ASSERT (h->plt.offset <= htab->splt->size);
 
      BFD_ASSERT (!h->def_regular);
 
 
 
      /* Calculate the address of the PLT header.  */
 
      header_address = (htab->splt->output_section->vma
 
                        + htab->splt->output_offset);
 
 
 
      /* Calculate the index of the entry.  */
 
      plt_index = ((h->plt.offset - htab->plt_header_size)
 
                   / htab->plt_entry_size);
 
 
 
      /* Calculate the address of the .got.plt entry.  */
 
      got_address = (htab->sgotplt->output_section->vma
 
                     + htab->sgotplt->output_offset
 
                     + (2 + plt_index) * MIPS_ELF_GOT_SIZE (dynobj));
 
      got_address_high = ((got_address + 0x8000) >> 16) & 0xffff;
 
      got_address_low = got_address & 0xffff;
 
 
 
      /* Initially point the .got.plt entry at the PLT header.  */
 
      loc = (htab->sgotplt->contents
 
             + (2 + plt_index) * MIPS_ELF_GOT_SIZE (dynobj));
 
      if (ABI_64_P (output_bfd))
 
        bfd_put_64 (output_bfd, header_address, loc);
 
      else
 
        bfd_put_32 (output_bfd, header_address, loc);
 
 
 
      /* Find out where the .plt entry should go.  */
 
      loc = htab->splt->contents + h->plt.offset;
 
 
 
      /* Pick the load opcode.  */
 
      load = MIPS_ELF_LOAD_WORD (output_bfd);
 
 
 
      /* Fill in the PLT entry itself.  */
 
      plt_entry = mips_exec_plt_entry;
 
      bfd_put_32 (output_bfd, plt_entry[0] | got_address_high, loc);
 
      bfd_put_32 (output_bfd, plt_entry[1] | got_address_low | load, loc + 4);
 
 
 
      if (! LOAD_INTERLOCKS_P (output_bfd))
 
        {
 
          bfd_put_32 (output_bfd, plt_entry[2] | got_address_low, loc + 8);
 
          bfd_put_32 (output_bfd, plt_entry[3], loc + 12);
 
        }
 
      else
 
        {
 
          bfd_put_32 (output_bfd, plt_entry[3], loc + 8);
 
          bfd_put_32 (output_bfd, plt_entry[2] | got_address_low, loc + 12);
 
        }
 
 
 
      /* Emit an R_MIPS_JUMP_SLOT relocation against the .got.plt entry.  */
 
      mips_elf_output_dynamic_relocation (output_bfd, htab->srelplt,
 
                                          plt_index, h->dynindx,
 
                                          R_MIPS_JUMP_SLOT, got_address);
 
 
 
      /* We distinguish between PLT entries and lazy-binding stubs by
 
         giving the former an st_other value of STO_MIPS_PLT.  Set the
 
         flag and leave the value if there are any relocations in the
 
         binary where pointer equality matters.  */
 
      sym->st_shndx = SHN_UNDEF;
 
      if (h->pointer_equality_needed)
 
        sym->st_other = STO_MIPS_PLT;
 
      else
 
        sym->st_value = 0;
 
    }
 
  else if (h->plt.offset != MINUS_ONE)
 
    {
 
      /* We've decided to create a lazy-binding stub.  */
      bfd_byte stub[MIPS_FUNCTION_STUB_BIG_SIZE];
      bfd_byte stub[MIPS_FUNCTION_STUB_BIG_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,
 
                                   MIPS_ELF_STUB_SECTION_NAME (dynobj));
 
      BFD_ASSERT (s != NULL);
 
 
 
      BFD_ASSERT ((htab->function_stub_size == MIPS_FUNCTION_STUB_BIG_SIZE)
      BFD_ASSERT ((htab->function_stub_size == MIPS_FUNCTION_STUB_BIG_SIZE)
                  || (h->dynindx <= 0xffff));
                  || (h->dynindx <= 0xffff));
 
 
      /* Values up to 2^31 - 1 are allowed.  Larger values would cause
      /* Values up to 2^31 - 1 are allowed.  Larger values would cause
         sign extension at runtime in the stub, resulting in a negative
         sign extension at runtime in the stub, resulting in a negative
Line 8542... Line 9455...
        bfd_put_32 (output_bfd, STUB_LI16U (h->dynindx & 0xffff), stub + idx);
        bfd_put_32 (output_bfd, STUB_LI16U (h->dynindx & 0xffff), stub + idx);
      else
      else
        bfd_put_32 (output_bfd, STUB_LI16S (output_bfd, h->dynindx),
        bfd_put_32 (output_bfd, STUB_LI16S (output_bfd, h->dynindx),
                    stub + idx);
                    stub + idx);
 
 
      BFD_ASSERT (h->plt.offset <= s->size);
      BFD_ASSERT (h->plt.offset <= htab->sstubs->size);
      memcpy (s->contents + h->plt.offset, stub, htab->function_stub_size);
      memcpy (htab->sstubs->contents + h->plt.offset,
 
              stub, htab->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
      sym->st_value = (htab->sstubs->output_section->vma
 
                       + htab->sstubs->output_offset
                       + h->plt.offset);
                       + h->plt.offset);
    }
    }
 
 
 
  /* If we have a MIPS16 function with a stub, the dynamic symbol must
 
     refer to the stub, since only the stub uses the standard calling
 
     conventions.  */
 
  if (h->dynindx != -1 && hmips->fn_stub != NULL)
 
    {
 
      BFD_ASSERT (hmips->need_fn_stub);
 
      sym->st_value = (hmips->fn_stub->output_section->vma
 
                       + hmips->fn_stub->output_offset);
 
      sym->st_size = hmips->fn_stub->size;
 
      sym->st_other = ELF_ST_VISIBILITY (sym->st_other);
 
    }
 
 
  BFD_ASSERT (h->dynindx != -1
  BFD_ASSERT (h->dynindx != -1
              || h->forced_local);
              || h->forced_local);
 
 
  sgot = mips_elf_got_section (dynobj, FALSE);
  sgot = htab->sgot;
  BFD_ASSERT (sgot != NULL);
  g = htab->got_info;
  BFD_ASSERT (mips_elf_section_data (sgot) != NULL);
 
  g = mips_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
  if (g->global_gotsym != NULL
Line 8574... Line 9499...
    {
    {
      bfd_vma offset;
      bfd_vma offset;
      bfd_vma value;
      bfd_vma value;
 
 
      value = sym->st_value;
      value = sym->st_value;
      offset = mips_elf_global_got_index (dynobj, output_bfd, h, R_MIPS_GOT16, info);
      offset = mips_elf_global_got_index (dynobj, output_bfd, h,
 
                                          R_MIPS_GOT16, info);
      MIPS_ELF_PUT_WORD (output_bfd, value, sgot->contents + offset);
      MIPS_ELF_PUT_WORD (output_bfd, value, sgot->contents + offset);
    }
    }
 
 
  if (g->next && h->dynindx != -1 && h->type != STT_TLS)
  if (g->next && h->dynindx != -1 && h->type != STT_TLS)
    {
    {
Line 8588... Line 9514...
 
 
      gg = g;
      gg = g;
 
 
      e.abfd = output_bfd;
      e.abfd = output_bfd;
      e.symndx = -1;
      e.symndx = -1;
      e.d.h = (struct mips_elf_link_hash_entry *)h;
      e.d.h = hmips;
      e.tls_type = 0;
      e.tls_type = 0;
 
 
      for (g = g->next; g->next != gg; g = g->next)
      for (g = g->next; g->next != gg; g = g->next)
        {
        {
          if (g->got_entries
          if (g->got_entries
Line 8675... Line 9601...
          else if (h->type == STT_OBJECT)
          else if (h->type == STT_OBJECT)
            sym->st_shndx = SHN_MIPS_DATA;
            sym->st_shndx = SHN_MIPS_DATA;
        }
        }
    }
    }
 
 
 
  /* Emit a copy reloc, if needed.  */
 
  if (h->needs_copy)
 
    {
 
      asection *s;
 
      bfd_vma symval;
 
 
 
      BFD_ASSERT (h->dynindx != -1);
 
      BFD_ASSERT (htab->use_plts_and_copy_relocs);
 
 
 
      s = mips_elf_rel_dyn_section (info, FALSE);
 
      symval = (h->root.u.def.section->output_section->vma
 
                + h->root.u.def.section->output_offset
 
                + h->root.u.def.value);
 
      mips_elf_output_dynamic_relocation (output_bfd, s, s->reloc_count++,
 
                                          h->dynindx, R_MIPS_COPY, symval);
 
    }
 
 
  /* Handle the IRIX6-specific symbols.  */
  /* Handle the IRIX6-specific symbols.  */
  if (IRIX_COMPAT (output_bfd) == ict_irix6)
  if (IRIX_COMPAT (output_bfd) == ict_irix6)
    mips_elf_irix6_finish_dynamic_symbol (output_bfd, name, sym);
    mips_elf_irix6_finish_dynamic_symbol (output_bfd, name, sym);
 
 
  if (! info->shared)
  if (! info->shared)
Line 8704... Line 9647...
                        != NULL);
                        != NULL);
          mips_elf_hash_table (info)->rld_value = sym->st_value;
          mips_elf_hash_table (info)->rld_value = sym->st_value;
        }
        }
    }
    }
 
 
  /* If this is a mips16 symbol, force the value to be even.  */
  /* Keep dynamic MIPS16 symbols odd.  This allows the dynamic linker to
  if (sym->st_other == STO_MIPS16)
     treat MIPS16 symbols like any other.  */
    sym->st_value &= ~1;
  if (ELF_ST_IS_MIPS16 (sym->st_other))
 
    {
 
      BFD_ASSERT (sym->st_value & 1);
 
      sym->st_other -= STO_MIPS16;
 
    }
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* Likewise, for VxWorks.  */
/* Likewise, for VxWorks.  */
Line 8826... Line 9773...
        sym->st_shndx = SHN_UNDEF;
        sym->st_shndx = SHN_UNDEF;
    }
    }
 
 
  BFD_ASSERT (h->dynindx != -1 || h->forced_local);
  BFD_ASSERT (h->dynindx != -1 || h->forced_local);
 
 
  sgot = mips_elf_got_section (dynobj, FALSE);
  sgot = htab->sgot;
  BFD_ASSERT (sgot != NULL);
  g = htab->got_info;
  BFD_ASSERT (mips_elf_section_data (sgot) != NULL);
 
  g = mips_elf_section_data (sgot)->u.got_info;
 
  BFD_ASSERT (g != NULL);
  BFD_ASSERT (g != NULL);
 
 
  /* See if this symbol has an entry in the GOT.  */
  /* See if this symbol has an entry in the GOT.  */
  if (g->global_gotsym != NULL
  if (g->global_gotsym != NULL
      && h->dynindx >= g->global_gotsym->dynindx)
      && h->dynindx >= g->global_gotsym->dynindx)
Line 8877... Line 9822...
                                    * sizeof (Elf32_External_Rela)));
                                    * sizeof (Elf32_External_Rela)));
      ++htab->srelbss->reloc_count;
      ++htab->srelbss->reloc_count;
    }
    }
 
 
  /* If this is a mips16 symbol, force the value to be even.  */
  /* If this is a mips16 symbol, force the value to be even.  */
  if (sym->st_other == STO_MIPS16)
  if (ELF_ST_IS_MIPS16 (sym->st_other))
    sym->st_value &= ~1;
    sym->st_value &= ~1;
 
 
  return TRUE;
  return TRUE;
}
}
 
 
 
/* Write out a plt0 entry to the beginning of .plt.  */
 
 
 
static void
 
mips_finish_exec_plt (bfd *output_bfd, struct bfd_link_info *info)
 
{
 
  bfd_byte *loc;
 
  bfd_vma gotplt_value, gotplt_value_high, gotplt_value_low;
 
  static const bfd_vma *plt_entry;
 
  struct mips_elf_link_hash_table *htab;
 
 
 
  htab = mips_elf_hash_table (info);
 
  if (ABI_64_P (output_bfd))
 
    plt_entry = mips_n64_exec_plt0_entry;
 
  else if (ABI_N32_P (output_bfd))
 
    plt_entry = mips_n32_exec_plt0_entry;
 
  else
 
    plt_entry = mips_o32_exec_plt0_entry;
 
 
 
  /* Calculate the value of .got.plt.  */
 
  gotplt_value = (htab->sgotplt->output_section->vma
 
                  + htab->sgotplt->output_offset);
 
  gotplt_value_high = ((gotplt_value + 0x8000) >> 16) & 0xffff;
 
  gotplt_value_low = gotplt_value & 0xffff;
 
 
 
  /* The PLT sequence is not safe for N64 if .got.plt's address can
 
     not be loaded in two instructions.  */
 
  BFD_ASSERT ((gotplt_value & ~(bfd_vma) 0x7fffffff) == 0
 
              || ~(gotplt_value | 0x7fffffff) == 0);
 
 
 
  /* Install the PLT header.  */
 
  loc = htab->splt->contents;
 
  bfd_put_32 (output_bfd, plt_entry[0] | gotplt_value_high, loc);
 
  bfd_put_32 (output_bfd, plt_entry[1] | gotplt_value_low, loc + 4);
 
  bfd_put_32 (output_bfd, plt_entry[2] | gotplt_value_low, loc + 8);
 
  bfd_put_32 (output_bfd, plt_entry[3], loc + 12);
 
  bfd_put_32 (output_bfd, plt_entry[4], loc + 16);
 
  bfd_put_32 (output_bfd, plt_entry[5], loc + 20);
 
  bfd_put_32 (output_bfd, plt_entry[6], loc + 24);
 
  bfd_put_32 (output_bfd, plt_entry[7], loc + 28);
 
}
 
 
/* Install the PLT header for a VxWorks executable and finalize the
/* Install the PLT header for a VxWorks executable and finalize the
   contents of .rela.plt.unloaded.  */
   contents of .rela.plt.unloaded.  */
 
 
static void
static void
mips_vxworks_finish_exec_plt (bfd *output_bfd, struct bfd_link_info *info)
mips_vxworks_finish_exec_plt (bfd *output_bfd, struct bfd_link_info *info)
Line 8990... Line 9976...
  htab = mips_elf_hash_table (info);
  htab = mips_elf_hash_table (info);
  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 = mips_elf_got_section (dynobj, FALSE);
  sgot = htab->sgot;
  if (sgot == NULL)
  gg = htab->got_info;
    gg = g = NULL;
 
  else
 
    {
 
      BFD_ASSERT (mips_elf_section_data (sgot) != NULL);
 
      gg = mips_elf_section_data (sgot)->u.got_info;
 
      BFD_ASSERT (gg != NULL);
 
      g = mips_elf_got_for_ibfd (gg, output_bfd);
 
      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;
      int dyn_to_skip = 0, dyn_skipped = 0;
      int dyn_to_skip = 0, dyn_skipped = 0;
 
 
      BFD_ASSERT (sdyn != NULL);
      BFD_ASSERT (sdyn != NULL);
 
      BFD_ASSERT (gg != NULL);
 
 
 
      g = mips_elf_got_for_ibfd (gg, output_bfd);
      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 += MIPS_ELF_DYN_SIZE (dynobj))
           b += MIPS_ELF_DYN_SIZE (dynobj))
Line 9044... Line 10024...
              dyn.d_un.d_val =
              dyn.d_un.d_val =
                _bfd_elf_strtab_size (elf_hash_table (info)->dynstr);
                _bfd_elf_strtab_size (elf_hash_table (info)->dynstr);
              break;
              break;
 
 
            case DT_PLTGOT:
            case DT_PLTGOT:
              name = ".got";
              s = htab->sgot;
              if (htab->is_vxworks)
              dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
                {
              break;
                  /* _GLOBAL_OFFSET_TABLE_ is defined to be the beginning
 
                     of the ".got" section in DYNOBJ.  */
            case DT_MIPS_PLTGOT:
                  s = bfd_get_section_by_name (dynobj, name);
              s = htab->sgotplt;
                  BFD_ASSERT (s != NULL);
 
                  dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
                  dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
                }
 
              else
 
                {
 
                  s = bfd_get_section_by_name (output_bfd, name);
 
                  BFD_ASSERT (s != NULL);
 
                  dyn.d_un.d_ptr = s->vma;
 
                }
 
              break;
              break;
 
 
            case DT_MIPS_RLD_VERSION:
            case DT_MIPS_RLD_VERSION:
              dyn.d_un.d_val = 1; /* XXX */
              dyn.d_un.d_val = 1; /* XXX */
              break;
              break;
Line 9124... Line 10096...
 
 
              dyn.d_un.d_val = s->size / elemsize;
              dyn.d_un.d_val = s->size / elemsize;
              break;
              break;
 
 
            case DT_MIPS_HIPAGENO:
            case DT_MIPS_HIPAGENO:
              dyn.d_un.d_val = g->local_gotno - MIPS_RESERVED_GOTNO (info);
              dyn.d_un.d_val = g->local_gotno - htab->reserved_gotno;
              break;
              break;
 
 
            case DT_MIPS_RLD_MAP:
            case DT_MIPS_RLD_MAP:
              dyn.d_un.d_ptr = mips_elf_hash_table (info)->rld_value;
              dyn.d_un.d_ptr = mips_elf_hash_table (info)->rld_value;
              break;
              break;
Line 9145... Line 10117...
              if (htab->srelplt)
              if (htab->srelplt)
                dyn.d_un.d_val -= htab->srelplt->size;
                dyn.d_un.d_val -= htab->srelplt->size;
              break;
              break;
 
 
            case DT_PLTREL:
            case DT_PLTREL:
              BFD_ASSERT (htab->is_vxworks);
              BFD_ASSERT (htab->use_plts_and_copy_relocs);
 
              if (htab->is_vxworks)
              dyn.d_un.d_val = DT_RELA;
              dyn.d_un.d_val = DT_RELA;
 
              else
 
                dyn.d_un.d_val = DT_REL;
              break;
              break;
 
 
            case DT_PLTRELSZ:
            case DT_PLTRELSZ:
              BFD_ASSERT (htab->is_vxworks);
              BFD_ASSERT (htab->use_plts_and_copy_relocs);
              dyn.d_un.d_val = htab->srelplt->size;
              dyn.d_un.d_val = htab->srelplt->size;
              break;
              break;
 
 
            case DT_JMPREL:
            case DT_JMPREL:
              BFD_ASSERT (htab->is_vxworks);
              BFD_ASSERT (htab->use_plts_and_copy_relocs);
              dyn.d_un.d_val = (htab->srelplt->output_section->vma
              dyn.d_un.d_ptr = (htab->srelplt->output_section->vma
                                + htab->srelplt->output_offset);
                                + htab->srelplt->output_offset);
              break;
              break;
 
 
            case DT_TEXTREL:
            case DT_TEXTREL:
              /* If we didn't need any text relocations after all, delete
              /* If we didn't need any text relocations after all, delete
Line 9228... Line 10203...
        {
        {
          /* 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.  */
          MIPS_ELF_PUT_WORD (output_bfd, (bfd_vma) 0, sgot->contents);
          MIPS_ELF_PUT_WORD (output_bfd, (bfd_vma) 0, sgot->contents);
          MIPS_ELF_PUT_WORD (output_bfd, (bfd_vma) 0x80000000,
          MIPS_ELF_PUT_WORD (output_bfd, MIPS_ELF_GNU_GOT1_MASK (output_bfd),
                             sgot->contents + MIPS_ELF_GOT_SIZE (output_bfd));
                             sgot->contents + MIPS_ELF_GOT_SIZE (output_bfd));
        }
        }
 
 
      elf_section_data (sgot->output_section)->this_hdr.sh_entsize
      elf_section_data (sgot->output_section)->this_hdr.sh_entsize
         = MIPS_ELF_GOT_SIZE (output_bfd);
         = MIPS_ELF_GOT_SIZE (output_bfd);
Line 9252... Line 10227...
          bfd_vma index = g->next->local_gotno + g->next->global_gotno
          bfd_vma index = g->next->local_gotno + g->next->global_gotno
            + g->next->tls_gotno;
            + g->next->tls_gotno;
 
 
          MIPS_ELF_PUT_WORD (output_bfd, 0, sgot->contents
          MIPS_ELF_PUT_WORD (output_bfd, 0, sgot->contents
                             + index++ * MIPS_ELF_GOT_SIZE (output_bfd));
                             + index++ * MIPS_ELF_GOT_SIZE (output_bfd));
          MIPS_ELF_PUT_WORD (output_bfd, 0x80000000, sgot->contents
          MIPS_ELF_PUT_WORD (output_bfd, MIPS_ELF_GNU_GOT1_MASK (output_bfd),
 
                             sgot->contents
                             + index++ * MIPS_ELF_GOT_SIZE (output_bfd));
                             + index++ * MIPS_ELF_GOT_SIZE (output_bfd));
 
 
          if (! info->shared)
          if (! info->shared)
            continue;
            continue;
 
 
Line 9347... Line 10323...
            bfd_elf32_swap_compact_rel_out (output_bfd, &cpt,
            bfd_elf32_swap_compact_rel_out (output_bfd, &cpt,
                                            ((Elf32_External_compact_rel *)
                                            ((Elf32_External_compact_rel *)
                                             s->contents));
                                             s->contents));
 
 
            /* Clean up a dummy stub function entry in .text.  */
            /* Clean up a dummy stub function entry in .text.  */
            s = bfd_get_section_by_name (dynobj,
            if (htab->sstubs != NULL)
                                         MIPS_ELF_STUB_SECTION_NAME (dynobj));
 
            if (s != NULL)
 
              {
              {
                file_ptr dummy_offset;
                file_ptr dummy_offset;
 
 
                BFD_ASSERT (s->size >= htab->function_stub_size);
                BFD_ASSERT (htab->sstubs->size >= htab->function_stub_size);
                dummy_offset = s->size - htab->function_stub_size;
                dummy_offset = htab->sstubs->size - htab->function_stub_size;
                memset (s->contents + dummy_offset, 0,
                memset (htab->sstubs->contents + dummy_offset, 0,
                        htab->function_stub_size);
                        htab->function_stub_size);
              }
              }
          }
          }
      }
      }
 
 
Line 9385... Line 10359...
                     sort_dynamic_relocs);
                     sort_dynamic_relocs);
          }
          }
      }
      }
  }
  }
 
 
  if (htab->is_vxworks && htab->splt->size > 0)
  if (htab->splt && htab->splt->size > 0)
 
    {
 
      if (htab->is_vxworks)
    {
    {
      if (info->shared)
      if (info->shared)
        mips_vxworks_finish_shared_plt (output_bfd, info);
        mips_vxworks_finish_shared_plt (output_bfd, info);
      else
      else
        mips_vxworks_finish_exec_plt (output_bfd, info);
        mips_vxworks_finish_exec_plt (output_bfd, info);
    }
    }
 
      else
 
        {
 
          BFD_ASSERT (!info->shared);
 
          mips_finish_exec_plt (output_bfd, info);
 
        }
 
    }
  return TRUE;
  return TRUE;
}
}
 
 
 
 
/* Set ABFD's EF_MIPS_ARCH and EF_MIPS_MACH flags.  */
/* Set ABFD's EF_MIPS_ARCH and EF_MIPS_MACH flags.  */
Line 9462... Line 10444...
    case bfd_mach_mips5000:
    case bfd_mach_mips5000:
    case bfd_mach_mips7000:
    case bfd_mach_mips7000:
    case bfd_mach_mips8000:
    case bfd_mach_mips8000:
    case bfd_mach_mips10000:
    case bfd_mach_mips10000:
    case bfd_mach_mips12000:
    case bfd_mach_mips12000:
 
    case bfd_mach_mips14000:
 
    case bfd_mach_mips16000:
      val = E_MIPS_ARCH_4;
      val = E_MIPS_ARCH_4;
      break;
      break;
 
 
    case bfd_mach_mips5:
    case bfd_mach_mips5:
      val = E_MIPS_ARCH_5;
      val = E_MIPS_ARCH_5;
Line 9485... Line 10469...
 
 
    case bfd_mach_mips_octeon:
    case bfd_mach_mips_octeon:
      val = E_MIPS_ARCH_64R2 | E_MIPS_MACH_OCTEON;
      val = E_MIPS_ARCH_64R2 | E_MIPS_MACH_OCTEON;
      break;
      break;
 
 
 
    case bfd_mach_mips_xlr:
 
      val = E_MIPS_ARCH_64 | E_MIPS_MACH_XLR;
 
      break;
 
 
    case bfd_mach_mipsisa32:
    case bfd_mach_mipsisa32:
      val = E_MIPS_ARCH_32;
      val = E_MIPS_ARCH_32;
      break;
      break;
 
 
    case bfd_mach_mipsisa64:
    case bfd_mach_mipsisa64:
Line 9933... Line 10921...
 
 
  relend = relocs + sec->reloc_count;
  relend = relocs + sec->reloc_count;
  for (rel = relocs; rel < relend; rel++)
  for (rel = relocs; rel < relend; rel++)
    switch (ELF_R_TYPE (abfd, rel->r_info))
    switch (ELF_R_TYPE (abfd, rel->r_info))
      {
      {
 
      case R_MIPS16_GOT16:
 
      case R_MIPS16_CALL16:
      case R_MIPS_GOT16:
      case R_MIPS_GOT16:
      case R_MIPS_CALL16:
      case R_MIPS_CALL16:
      case R_MIPS_CALL_HI16:
      case R_MIPS_CALL_HI16:
      case R_MIPS_CALL_LO16:
      case R_MIPS_CALL_LO16:
      case R_MIPS_GOT_HI16:
      case R_MIPS_GOT_HI16:
Line 9969... Line 10959...
{
{
  struct mips_elf_link_hash_entry *dirmips, *indmips;
  struct mips_elf_link_hash_entry *dirmips, *indmips;
 
 
  _bfd_elf_link_hash_copy_indirect (info, dir, ind);
  _bfd_elf_link_hash_copy_indirect (info, dir, ind);
 
 
 
  dirmips = (struct mips_elf_link_hash_entry *) dir;
 
  indmips = (struct mips_elf_link_hash_entry *) ind;
 
  /* Any absolute non-dynamic relocations against an indirect or weak
 
     definition will be against the target symbol.  */
 
  if (indmips->has_static_relocs)
 
    dirmips->has_static_relocs = TRUE;
 
 
  if (ind->root.type != bfd_link_hash_indirect)
  if (ind->root.type != bfd_link_hash_indirect)
    return;
    return;
 
 
  dirmips = (struct mips_elf_link_hash_entry *) dir;
 
  indmips = (struct mips_elf_link_hash_entry *) ind;
 
  dirmips->possibly_dynamic_relocs += indmips->possibly_dynamic_relocs;
  dirmips->possibly_dynamic_relocs += indmips->possibly_dynamic_relocs;
  if (indmips->readonly_reloc)
  if (indmips->readonly_reloc)
    dirmips->readonly_reloc = TRUE;
    dirmips->readonly_reloc = TRUE;
  if (indmips->no_fn_stub)
  if (indmips->no_fn_stub)
    dirmips->no_fn_stub = TRUE;
    dirmips->no_fn_stub = TRUE;
 
  if (indmips->fn_stub)
  if (dirmips->tls_type == 0)
 
    dirmips->tls_type = indmips->tls_type;
 
}
 
 
 
void
 
_bfd_mips_elf_hide_symbol (struct bfd_link_info *info,
 
                           struct elf_link_hash_entry *entry,
 
                           bfd_boolean force_local)
 
{
 
  bfd *dynobj;
 
  asection *got;
 
  struct mips_got_info *g;
 
  struct mips_elf_link_hash_entry *h;
 
  struct mips_elf_link_hash_table *htab;
 
 
 
  h = (struct mips_elf_link_hash_entry *) entry;
 
  if (h->forced_local)
 
    return;
 
  h->forced_local = force_local;
 
 
 
  dynobj = elf_hash_table (info)->dynobj;
 
  htab = mips_elf_hash_table (info);
 
  if (dynobj != NULL && force_local && h->root.type != STT_TLS
 
      && (got = mips_elf_got_section (dynobj, TRUE)) != NULL
 
      && (g = mips_elf_section_data (got)->u.got_info) != NULL)
 
    {
 
      if (g->next)
 
        {
 
          struct mips_got_entry e;
 
          struct mips_got_info *gg = g;
 
 
 
          /* 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
 
             that had an entry for it.  This will automatically decrease
 
             the number of global entries, since global_gotno is actually
 
             the upper limit of global entries.  */
 
          e.abfd = dynobj;
 
          e.symndx = -1;
 
          e.d.h = h;
 
          e.tls_type = 0;
 
 
 
          for (g = g->next; g != gg; g = g->next)
 
            if (htab_find (g->got_entries, &e))
 
              {
              {
                BFD_ASSERT (g->global_gotno > 0);
      dirmips->fn_stub = indmips->fn_stub;
                g->local_gotno++;
      indmips->fn_stub = NULL;
                g->global_gotno--;
 
              }
              }
 
  if (indmips->need_fn_stub)
          /* 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
 
             at this point, but we must at least stop counting it as one
 
             of the symbols that required a forced got entry.  */
 
          if (h->root.got.offset == 2)
 
            {
            {
              BFD_ASSERT (gg->assigned_gotno > 0);
      dirmips->need_fn_stub = TRUE;
              gg->assigned_gotno--;
      indmips->need_fn_stub = FALSE;
            }
            }
        }
  if (indmips->call_stub)
      else if (h->root.got.offset == 1)
 
        {
 
          /* check_relocs didn't know that this symbol would be
 
             forced-local, so add an extra local got entry.  */
 
          g->local_gotno++;
 
          if (htab->computed_got_sizes)
 
            {
            {
              /* We'll have treated this symbol as global rather
      dirmips->call_stub = indmips->call_stub;
                 than local.  */
      indmips->call_stub = NULL;
              BFD_ASSERT (g->global_gotno > 0);
 
              g->global_gotno--;
 
            }
 
        }
        }
      else if (htab->is_vxworks && h->root.needs_plt)
  if (indmips->call_fp_stub)
        {
        {
          /* check_relocs didn't know that this symbol would be
      dirmips->call_fp_stub = indmips->call_fp_stub;
             forced-local, so add an extra local got entry.  */
      indmips->call_fp_stub = NULL;
          g->local_gotno++;
 
          if (htab->computed_got_sizes)
 
            /* The symbol is only used in call relocations, so we'll
 
               have assumed it only needs a .got.plt entry.  Increase
 
               the size of .got accordingly.  */
 
            got->size += MIPS_ELF_GOT_SIZE (dynobj);
 
        }
 
    }
    }
 
  if (indmips->global_got_area < dirmips->global_got_area)
 
    dirmips->global_got_area = indmips->global_got_area;
 
  if (indmips->global_got_area < GGA_NONE)
 
    indmips->global_got_area = GGA_NONE;
 
  if (indmips->has_nonpic_branches)
 
    dirmips->has_nonpic_branches = TRUE;
 
 
  _bfd_elf_link_hash_hide_symbol (info, &h->root, force_local);
  if (dirmips->tls_type == 0)
 
    dirmips->tls_type = indmips->tls_type;
}
}


#define PDR_SIZE 32
#define PDR_SIZE 32
 
 
bfd_boolean
bfd_boolean
Line 10493... Line 11430...
  if (reloc_vector != NULL)
  if (reloc_vector != NULL)
    free (reloc_vector);
    free (reloc_vector);
  return NULL;
  return NULL;
}
}


 
/* Allocate ABFD's target-dependent data.  */
 
 
 
bfd_boolean
 
_bfd_mips_elf_mkobject (bfd *abfd)
 
{
 
  return bfd_elf_allocate_object (abfd, sizeof (struct elf_obj_tdata),
 
                                  MIPS_ELF_TDATA);
 
}
 
 
/* Create a MIPS ELF linker hash table.  */
/* Create a MIPS ELF linker hash table.  */
 
 
struct bfd_link_hash_table *
struct bfd_link_hash_table *
_bfd_mips_elf_link_hash_table_create (bfd *abfd)
_bfd_mips_elf_link_hash_table_create (bfd *abfd)
{
{
Line 10523... Line 11469...
  ret->procedure_count = 0;
  ret->procedure_count = 0;
  ret->compact_rel_size = 0;
  ret->compact_rel_size = 0;
  ret->use_rld_obj_head = FALSE;
  ret->use_rld_obj_head = FALSE;
  ret->rld_value = 0;
  ret->rld_value = 0;
  ret->mips16_stubs_seen = FALSE;
  ret->mips16_stubs_seen = FALSE;
  ret->computed_got_sizes = FALSE;
  ret->use_plts_and_copy_relocs = FALSE;
  ret->is_vxworks = FALSE;
  ret->is_vxworks = FALSE;
  ret->small_data_overflow_reported = FALSE;
  ret->small_data_overflow_reported = FALSE;
  ret->srelbss = NULL;
  ret->srelbss = NULL;
  ret->sdynbss = NULL;
  ret->sdynbss = NULL;
  ret->srelplt = NULL;
  ret->srelplt = NULL;
  ret->srelplt2 = NULL;
  ret->srelplt2 = NULL;
  ret->sgotplt = NULL;
  ret->sgotplt = NULL;
  ret->splt = NULL;
  ret->splt = NULL;
 
  ret->sstubs = NULL;
 
  ret->sgot = NULL;
 
  ret->got_info = NULL;
  ret->plt_header_size = 0;
  ret->plt_header_size = 0;
  ret->plt_entry_size = 0;
  ret->plt_entry_size = 0;
 
  ret->lazy_stub_count = 0;
  ret->function_stub_size = 0;
  ret->function_stub_size = 0;
 
  ret->strampoline = NULL;
 
  ret->la25_stubs = NULL;
 
  ret->add_stub_section = NULL;
 
 
  return &ret->root.root;
  return &ret->root.root;
}
}
 
 
/* Likewise, but indicate that the target is VxWorks.  */
/* Likewise, but indicate that the target is VxWorks.  */
Line 10552... Line 11505...
  if (ret)
  if (ret)
    {
    {
      struct mips_elf_link_hash_table *htab;
      struct mips_elf_link_hash_table *htab;
 
 
      htab = (struct mips_elf_link_hash_table *) ret;
      htab = (struct mips_elf_link_hash_table *) ret;
      htab->is_vxworks = 1;
      htab->use_plts_and_copy_relocs = TRUE;
 
      htab->is_vxworks = TRUE;
    }
    }
  return ret;
  return ret;
}
}
 
 
 
/* A function that the linker calls if we are allowed to use PLTs
 
   and copy relocs.  */
 
 
 
void
 
_bfd_mips_elf_use_plts_and_copy_relocs (struct bfd_link_info *info)
 
{
 
  mips_elf_hash_table (info)->use_plts_and_copy_relocs = TRUE;
 
}


/* We need to use a special link routine to handle the .reginfo and
/* We need to use a special link routine to handle the .reginfo and
   the .mdebug sections.  We need to merge all instances of these
   the .mdebug sections.  We need to merge all instances of these
   sections together, not write them all out sequentially.  */
   sections together, not write them all out sequentially.  */
 
 
Line 10570... Line 11533...
  struct bfd_link_order *p;
  struct bfd_link_order *p;
  asection *reginfo_sec, *mdebug_sec, *gptab_data_sec, *gptab_bss_sec;
  asection *reginfo_sec, *mdebug_sec, *gptab_data_sec, *gptab_bss_sec;
  asection *rtproc_sec;
  asection *rtproc_sec;
  Elf32_RegInfo reginfo;
  Elf32_RegInfo reginfo;
  struct ecoff_debug_info debug;
  struct ecoff_debug_info debug;
 
  struct mips_htab_traverse_info hti;
  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
  const struct ecoff_debug_swap *swap = bed->elf_backend_ecoff_debug_swap;
  const struct ecoff_debug_swap *swap = bed->elf_backend_ecoff_debug_swap;
  HDRR *symhdr = &debug.symbolic_header;
  HDRR *symhdr = &debug.symbolic_header;
  void *mdebug_handle = NULL;
  void *mdebug_handle = NULL;
  asection *s;
  asection *s;
Line 10591... Line 11555...
  {
  {
    scText, scInit, scFini, scData,
    scText, scInit, scFini, scData,
    scRData, scSData, scSBss, scBss
    scRData, scSData, scSBss, scBss
  };
  };
 
 
  /* We'd carefully arranged the dynamic symbol indices, and then the
  /* Sort the dynamic symbols so that those with GOT entries come after
     generic size_dynamic_sections renumbered them out from under us.
     those without.  */
     Rather than trying somehow to prevent the renumbering, just do
 
     the sort again.  */
 
  htab = mips_elf_hash_table (info);
  htab = mips_elf_hash_table (info);
  if (elf_hash_table (info)->dynamic_sections_created)
  if (!mips_elf_sort_hash_table (abfd, info))
    {
 
      bfd *dynobj;
 
      asection *got;
 
      struct mips_got_info *g;
 
      bfd_size_type dynsecsymcount;
 
 
 
      /* When we resort, we must tell mips_elf_sort_hash_table what
 
         the lowest index it may use is.  That's the number of section
 
         symbols we're going to add.  The generic ELF linker only
 
         adds these symbols when building a shared object.  Note that
 
         we count the sections after (possibly) removing the .options
 
         section above.  */
 
 
 
      dynsecsymcount = count_section_dynsyms (abfd, info);
 
      if (! mips_elf_sort_hash_table (info, dynsecsymcount + 1))
 
        return FALSE;
        return FALSE;
 
 
      /* Make sure we didn't grow the global .got region.  */
  /* Create any scheduled LA25 stubs.  */
      dynobj = elf_hash_table (info)->dynobj;
  hti.info = info;
      got = mips_elf_got_section (dynobj, FALSE);
  hti.output_bfd = abfd;
      g = mips_elf_section_data (got)->u.got_info;
  hti.error = FALSE;
 
  htab_traverse (htab->la25_stubs, mips_elf_create_la25_stub, &hti);
      if (g->global_gotsym != NULL)
  if (hti.error)
        BFD_ASSERT ((elf_hash_table (info)->dynsymcount
    return FALSE;
                     - g->global_gotsym->dynindx)
 
                    <= g->global_gotno);
 
    }
 
 
 
  /* Get a value for the GP register.  */
  /* Get a value for the GP register.  */
  if (elf_gp (abfd) == 0)
  if (elf_gp (abfd) == 0)
    {
    {
      struct bfd_link_hash_entry *h;
      struct bfd_link_hash_entry *h;
Line 10814... Line 11758...
                }
                }
 
 
              input_section = p->u.indirect.section;
              input_section = p->u.indirect.section;
              input_bfd = input_section->owner;
              input_bfd = input_section->owner;
 
 
              if (bfd_get_flavour (input_bfd) != bfd_target_elf_flavour
              if (!is_mips_elf (input_bfd))
                  || (get_elf_backend_data (input_bfd)
 
                      ->elf_backend_ecoff_debug_swap) == NULL)
 
                {
                {
                  /* I don't know what a non MIPS ELF bfd would be
                  /* I don't know what a non MIPS ELF bfd would be
                     doing with a .mdebug section, but I don't really
                     doing with a .mdebug section, but I don't really
                     want to deal with it.  */
                     want to deal with it.  */
                  continue;
                  continue;
Line 11226... Line 12168...
  { bfd_mach_mips_octeon, bfd_mach_mipsisa64r2 },
  { bfd_mach_mips_octeon, bfd_mach_mipsisa64r2 },
 
 
  /* MIPS64 extensions.  */
  /* MIPS64 extensions.  */
  { bfd_mach_mipsisa64r2, bfd_mach_mipsisa64 },
  { bfd_mach_mipsisa64r2, bfd_mach_mipsisa64 },
  { bfd_mach_mips_sb1, bfd_mach_mipsisa64 },
  { bfd_mach_mips_sb1, bfd_mach_mipsisa64 },
 
  { bfd_mach_mips_xlr, bfd_mach_mipsisa64 },
 
 
  /* MIPS V extensions.  */
  /* MIPS V extensions.  */
  { bfd_mach_mipsisa64, bfd_mach_mips5 },
  { bfd_mach_mipsisa64, bfd_mach_mips5 },
 
 
  /* R10000 extensions.  */
  /* R10000 extensions.  */
  { bfd_mach_mips12000, bfd_mach_mips10000 },
  { bfd_mach_mips12000, bfd_mach_mips10000 },
 
  { bfd_mach_mips14000, bfd_mach_mips10000 },
 
  { bfd_mach_mips16000, bfd_mach_mips10000 },
 
 
  /* R5000 extensions.  Note: the vr5500 ISA is an extension of the core
  /* R5000 extensions.  Note: the vr5500 ISA is an extension of the core
     vr5400 ISA, but doesn't include the multimedia stuff.  It seems
     vr5400 ISA, but doesn't include the multimedia stuff.  It seems
     better to allow vr5400 and vr5500 code to be merged anyway, since
     better to allow vr5400 and vr5500 code to be merged anyway, since
     many libraries will just use the core ISA.  Perhaps we could add
     many libraries will just use the core ISA.  Perhaps we could add
Line 11489... Line 12434...
        (_("%B: endianness incompatible with that of the selected emulation"),
        (_("%B: endianness incompatible with that of the selected emulation"),
         ibfd);
         ibfd);
      return FALSE;
      return FALSE;
    }
    }
 
 
  if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
  if (!is_mips_elf (ibfd) || !is_mips_elf (obfd))
      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
 
    return TRUE;
    return TRUE;
 
 
  if (strcmp (bfd_get_target (ibfd), bfd_get_target (obfd)) != 0)
  if (strcmp (bfd_get_target (ibfd), bfd_get_target (obfd)) != 0)
    {
    {
      (*_bfd_error_handler)
      (*_bfd_error_handler)
Line 11543... Line 12487...
  /* MIPSpro generates ucode info in n64 objects.  Again, we should
  /* MIPSpro generates ucode info in n64 objects.  Again, we should
     just be able to ignore this.  */
     just be able to ignore this.  */
  new_flags &= ~EF_MIPS_UCODE;
  new_flags &= ~EF_MIPS_UCODE;
  old_flags &= ~EF_MIPS_UCODE;
  old_flags &= ~EF_MIPS_UCODE;
 
 
  /* Don't care about the PIC flags from dynamic objects; they are
  /* DSOs should only be linked with CPIC code.  */
     PIC by design.  */
  if ((ibfd->flags & DYNAMIC) != 0)
  if ((new_flags & (EF_MIPS_PIC | EF_MIPS_CPIC)) != 0
    new_flags |= EF_MIPS_PIC | EF_MIPS_CPIC;
      && (ibfd->flags & DYNAMIC) != 0)
 
    new_flags &= ~ (EF_MIPS_PIC | EF_MIPS_CPIC);
 
 
 
  if (new_flags == old_flags)
  if (new_flags == old_flags)
    return TRUE;
    return TRUE;
 
 
  /* Check to see if the input BFD actually contains any sections.
  /* Check to see if the input BFD actually contains any sections.
Line 11579... Line 12521...
 
 
  if (((new_flags & (EF_MIPS_PIC | EF_MIPS_CPIC)) != 0)
  if (((new_flags & (EF_MIPS_PIC | EF_MIPS_CPIC)) != 0)
      != ((old_flags & (EF_MIPS_PIC | EF_MIPS_CPIC)) != 0))
      != ((old_flags & (EF_MIPS_PIC | EF_MIPS_CPIC)) != 0))
    {
    {
      (*_bfd_error_handler)
      (*_bfd_error_handler)
        (_("%B: warning: linking PIC files with non-PIC files"),
        (_("%B: warning: linking abicalls files with non-abicalls files"),
         ibfd);
         ibfd);
      ok = TRUE;
      ok = TRUE;
    }
    }
 
 
  if (new_flags & (EF_MIPS_PIC | EF_MIPS_CPIC))
  if (new_flags & (EF_MIPS_PIC | EF_MIPS_CPIC))
Line 11698... Line 12640...
  elf_elfheader (abfd)->e_flags = flags;
  elf_elfheader (abfd)->e_flags = flags;
  elf_flags_init (abfd) = TRUE;
  elf_flags_init (abfd) = TRUE;
  return TRUE;
  return TRUE;
}
}
 
 
 
char *
 
_bfd_mips_elf_get_target_dtag (bfd_vma dtag)
 
{
 
  switch (dtag)
 
    {
 
    default: return "";
 
    case DT_MIPS_RLD_VERSION:
 
      return "MIPS_RLD_VERSION";
 
    case DT_MIPS_TIME_STAMP:
 
      return "MIPS_TIME_STAMP";
 
    case DT_MIPS_ICHECKSUM:
 
      return "MIPS_ICHECKSUM";
 
    case DT_MIPS_IVERSION:
 
      return "MIPS_IVERSION";
 
    case DT_MIPS_FLAGS:
 
      return "MIPS_FLAGS";
 
    case DT_MIPS_BASE_ADDRESS:
 
      return "MIPS_BASE_ADDRESS";
 
    case DT_MIPS_MSYM:
 
      return "MIPS_MSYM";
 
    case DT_MIPS_CONFLICT:
 
      return "MIPS_CONFLICT";
 
    case DT_MIPS_LIBLIST:
 
      return "MIPS_LIBLIST";
 
    case DT_MIPS_LOCAL_GOTNO:
 
      return "MIPS_LOCAL_GOTNO";
 
    case DT_MIPS_CONFLICTNO:
 
      return "MIPS_CONFLICTNO";
 
    case DT_MIPS_LIBLISTNO:
 
      return "MIPS_LIBLISTNO";
 
    case DT_MIPS_SYMTABNO:
 
      return "MIPS_SYMTABNO";
 
    case DT_MIPS_UNREFEXTNO:
 
      return "MIPS_UNREFEXTNO";
 
    case DT_MIPS_GOTSYM:
 
      return "MIPS_GOTSYM";
 
    case DT_MIPS_HIPAGENO:
 
      return "MIPS_HIPAGENO";
 
    case DT_MIPS_RLD_MAP:
 
      return "MIPS_RLD_MAP";
 
    case DT_MIPS_DELTA_CLASS:
 
      return "MIPS_DELTA_CLASS";
 
    case DT_MIPS_DELTA_CLASS_NO:
 
      return "MIPS_DELTA_CLASS_NO";
 
    case DT_MIPS_DELTA_INSTANCE:
 
      return "MIPS_DELTA_INSTANCE";
 
    case DT_MIPS_DELTA_INSTANCE_NO:
 
      return "MIPS_DELTA_INSTANCE_NO";
 
    case DT_MIPS_DELTA_RELOC:
 
      return "MIPS_DELTA_RELOC";
 
    case DT_MIPS_DELTA_RELOC_NO:
 
      return "MIPS_DELTA_RELOC_NO";
 
    case DT_MIPS_DELTA_SYM:
 
      return "MIPS_DELTA_SYM";
 
    case DT_MIPS_DELTA_SYM_NO:
 
      return "MIPS_DELTA_SYM_NO";
 
    case DT_MIPS_DELTA_CLASSSYM:
 
      return "MIPS_DELTA_CLASSSYM";
 
    case DT_MIPS_DELTA_CLASSSYM_NO:
 
      return "MIPS_DELTA_CLASSSYM_NO";
 
    case DT_MIPS_CXX_FLAGS:
 
      return "MIPS_CXX_FLAGS";
 
    case DT_MIPS_PIXIE_INIT:
 
      return "MIPS_PIXIE_INIT";
 
    case DT_MIPS_SYMBOL_LIB:
 
      return "MIPS_SYMBOL_LIB";
 
    case DT_MIPS_LOCALPAGE_GOTIDX:
 
      return "MIPS_LOCALPAGE_GOTIDX";
 
    case DT_MIPS_LOCAL_GOTIDX:
 
      return "MIPS_LOCAL_GOTIDX";
 
    case DT_MIPS_HIDDEN_GOTIDX:
 
      return "MIPS_HIDDEN_GOTIDX";
 
    case DT_MIPS_PROTECTED_GOTIDX:
 
      return "MIPS_PROTECTED_GOT_IDX";
 
    case DT_MIPS_OPTIONS:
 
      return "MIPS_OPTIONS";
 
    case DT_MIPS_INTERFACE:
 
      return "MIPS_INTERFACE";
 
    case DT_MIPS_DYNSTR_ALIGN:
 
      return "DT_MIPS_DYNSTR_ALIGN";
 
    case DT_MIPS_INTERFACE_SIZE:
 
      return "DT_MIPS_INTERFACE_SIZE";
 
    case DT_MIPS_RLD_TEXT_RESOLVE_ADDR:
 
      return "DT_MIPS_RLD_TEXT_RESOLVE_ADDR";
 
    case DT_MIPS_PERF_SUFFIX:
 
      return "DT_MIPS_PERF_SUFFIX";
 
    case DT_MIPS_COMPACT_SIZE:
 
      return "DT_MIPS_COMPACT_SIZE";
 
    case DT_MIPS_GP_VALUE:
 
      return "DT_MIPS_GP_VALUE";
 
    case DT_MIPS_AUX_DYNAMIC:
 
      return "DT_MIPS_AUX_DYNAMIC";
 
    case DT_MIPS_PLTGOT:
 
      return "DT_MIPS_PLTGOT";
 
    case DT_MIPS_RWPLT:
 
      return "DT_MIPS_RWPLT";
 
    }
 
}
 
 
bfd_boolean
bfd_boolean
_bfd_mips_elf_print_private_bfd_data (bfd *abfd, void *ptr)
_bfd_mips_elf_print_private_bfd_data (bfd *abfd, void *ptr)
{
{
  FILE *file = ptr;
  FILE *file = ptr;
 
 
Line 11830... Line 12871...
  return (sym->st_shndx == SHN_COMMON
  return (sym->st_shndx == SHN_COMMON
          || sym->st_shndx == SHN_MIPS_ACOMMON
          || sym->st_shndx == SHN_MIPS_ACOMMON
          || sym->st_shndx == SHN_MIPS_SCOMMON);
          || sym->st_shndx == SHN_MIPS_SCOMMON);
}
}
 
 
 No newline at end of file
 No newline at end of file
 
/* Return address for Ith PLT stub in section PLT, for relocation REL
 
   or (bfd_vma) -1 if it should not be included.  */
 
 
 
bfd_vma
 
_bfd_mips_elf_plt_sym_val (bfd_vma i, const asection *plt,
 
                           const arelent *rel ATTRIBUTE_UNUSED)
 
{
 
  return (plt->vma
 
          + 4 * ARRAY_SIZE (mips_o32_exec_plt0_entry)
 
          + i * 4 * ARRAY_SIZE (mips_exec_plt_entry));
 
}
 
 
 
void
 
_bfd_mips_post_process_headers (bfd *abfd, struct bfd_link_info *link_info)
 
{
 
  struct mips_elf_link_hash_table *htab;
 
  Elf_Internal_Ehdr *i_ehdrp;
 
 
 
  i_ehdrp = elf_elfheader (abfd);
 
  if (link_info)
 
    {
 
      htab = mips_elf_hash_table (link_info);
 
      if (htab->use_plts_and_copy_relocs && !htab->is_vxworks)
 
        i_ehdrp->e_ident[EI_ABIVERSION] = 1;
 
    }
 
}
 
 
 No newline at end of file
 No newline at end of file

powered by: WebSVN 2.1.0

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