blob: 59444b063a440b457e67e35d9640d830cc276f9d [file] [log] [blame]
/* MIPS-specific support for ELF
Copyright (C) 1993-2024 Free Software Foundation, Inc.
Most of the information added by Ian Lance Taylor, Cygnus Support,
<ian@cygnus.com>.
N32/64 ABI support added by Mark Mitchell, CodeSourcery, LLC.
<mark@codesourcery.com>
Traditional MIPS targets support added by Koundinya.K, Dansk Data
Elektronik & Operations Research Group. <kk@ddeorg.soft.net>
This file is part of BFD, the Binary File Descriptor library.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
/* This file handles functionality common to the different MIPS ABI's. */
#include "sysdep.h"
#include "bfd.h"
#include "libbfd.h"
#include "libiberty.h"
#include "elf-bfd.h"
#include "ecoff-bfd.h"
#include "elfxx-mips.h"
#include "elf/mips.h"
#include "elf-vxworks.h"
#include "dwarf2.h"
/* Get the ECOFF swapping routines. */
#include "coff/sym.h"
#include "coff/symconst.h"
#include "coff/ecoff.h"
#include "coff/mips.h"
#include "hashtab.h"
/* Types of TLS GOT entry. */
enum mips_got_tls_type {
GOT_TLS_NONE,
GOT_TLS_GD,
GOT_TLS_LDM,
GOT_TLS_IE
};
/* This structure is used to hold information about one GOT entry.
There are four types of entry:
(1) an absolute address
requires: abfd == NULL
fields: d.address
(2) a SYMBOL + OFFSET address, where SYMBOL is local to an input bfd
requires: abfd != NULL, symndx >= 0, tls_type != GOT_TLS_LDM
fields: abfd, symndx, d.addend, tls_type
(3) a SYMBOL address, where SYMBOL is not local to an input bfd
requires: abfd != NULL, symndx == -1
fields: d.h, tls_type
(4) a TLS LDM slot
requires: abfd != NULL, symndx == 0, tls_type == GOT_TLS_LDM
fields: none; there's only one of these per GOT. */
struct mips_got_entry
{
/* One input bfd that needs the GOT entry. */
bfd *abfd;
/* The index of the symbol, as stored in the relocation r_info, if
we have a local symbol; -1 otherwise. */
long symndx;
union
{
/* If abfd == NULL, an address that must be stored in the got. */
bfd_vma address;
/* If abfd != NULL && symndx != -1, the addend of the relocation
that should be added to the symbol value. */
bfd_vma addend;
/* If abfd != NULL && symndx == -1, the hash table entry
corresponding to a symbol in the GOT. The symbol's entry
is in the local area if h->global_got_area is GGA_NONE,
otherwise it is in the global area. */
struct mips_elf_link_hash_entry *h;
} d;
/* The TLS type of this GOT entry. An LDM GOT entry will be a local
symbol entry with r_symndx == 0. */
unsigned char tls_type;
/* True if we have filled in the GOT contents for a TLS entry,
and created the associated relocations. */
unsigned char tls_initialized;
/* The offset from the beginning of the .got section to the entry
corresponding to this symbol+addend. If it's a global symbol
whose offset is yet to be decided, it's going to be -1. */
long gotidx;
};
/* This structure represents a GOT page reference from an input bfd.
Each instance represents a symbol + ADDEND, where the representation
of the symbol depends on whether it is local to the input bfd.
If it is, then SYMNDX >= 0, and the symbol has index SYMNDX in U.ABFD.
Otherwise, SYMNDX < 0 and U.H points to the symbol's hash table entry.
Page references with SYMNDX >= 0 always become page references
in the output. Page references with SYMNDX < 0 only become page
references if the symbol binds locally; in other cases, the page
reference decays to a global GOT reference. */
struct mips_got_page_ref
{
long symndx;
union
{
struct mips_elf_link_hash_entry *h;
bfd *abfd;
} u;
bfd_vma addend;
};
/* This structure describes a range of addends: [MIN_ADDEND, MAX_ADDEND].
The structures form a non-overlapping list that is sorted by increasing
MIN_ADDEND. */
struct mips_got_page_range
{
struct mips_got_page_range *next;
bfd_signed_vma min_addend;
bfd_signed_vma max_addend;
};
/* This structure describes the range of addends that are applied to page
relocations against a given section. */
struct mips_got_page_entry
{
/* The section that these entries are based on. */
asection *sec;
/* The ranges for this page entry. */
struct mips_got_page_range *ranges;
/* The maximum number of page entries needed for RANGES. */
bfd_vma num_pages;
};
/* This structure is used to hold .got information when linking. */
struct mips_got_info
{
/* The number of global .got entries. */
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. */
unsigned int tls_gotno;
/* The first unused TLS .got entry. Used only during
mips_elf_initialize_tls_index. */
unsigned int tls_assigned_gotno;
/* The number of local .got entries, eventually including page entries. */
unsigned int local_gotno;
/* The maximum number of page entries needed. */
unsigned int page_gotno;
/* The number of relocations needed for the GOT entries. */
unsigned int relocs;
/* The first unused local .got entry. */
unsigned int assigned_low_gotno;
/* The last unused local .got entry. */
unsigned int assigned_high_gotno;
/* A hash table holding members of the got. */
struct htab *got_entries;
/* A hash table holding mips_got_page_ref structures. */
struct htab *got_page_refs;
/* A hash table of mips_got_page_entry structures. */
struct htab *got_page_entries;
/* In multi-got links, a pointer to the next got (err, rather, most
of the time, it points to the previous got). */
struct mips_got_info *next;
};
/* Structure passed when merging bfds' gots. */
struct mips_elf_got_per_bfd_arg
{
/* The output bfd. */
bfd *obfd;
/* The link information. */
struct bfd_link_info *info;
/* A pointer to the primary got, i.e., the one that's going to get
the implicit relocations from DT_MIPS_LOCAL_GOTNO and
DT_MIPS_GOTSYM. */
struct mips_got_info *primary;
/* A non-primary got we're trying to merge with other input bfd's
gots. */
struct mips_got_info *current;
/* The maximum number of got entries that can be addressed with a
16-bit offset. */
unsigned int max_count;
/* The maximum number of page entries needed by each got. */
unsigned int max_pages;
/* The total number of global entries which will live in the
primary got and be automatically relocated. This includes
those not referenced by the primary GOT but included in
the "master" GOT. */
unsigned int global_count;
};
/* A structure used to pass information to htab_traverse callbacks
when laying out the GOT. */
struct mips_elf_traverse_got_arg
{
struct bfd_link_info *info;
struct mips_got_info *g;
int value;
};
struct _mips_elf_section_data
{
struct bfd_elf_section_data elf;
union
{
bfd_byte *tdata;
} u;
};
#define mips_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_DATA)
/* 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_BC(VAL) (0xc8000000 | (((VAL) >> 2) & 0x3ffffff)) /* bc VAL */
#define LA25_ADDIU(VAL) (0x27390000 | (VAL)) /* addiu t9,t9,VAL */
#define LA25_LUI_MICROMIPS(VAL) \
(0x41b90000 | (VAL)) /* lui t9,VAL */
#define LA25_J_MICROMIPS(VAL) \
(0xd4000000 | (((VAL) >> 1) & 0x3ffffff)) /* j VAL */
#define LA25_ADDIU_MICROMIPS(VAL) \
(0x33390000 | (VAL)) /* addiu t9,t9,VAL */
/* This structure is passed to mips_elf_sort_hash_table_f when sorting
the dynamic symbols. */
struct mips_elf_hash_sort_data
{
/* The symbol in the global GOT with the lowest dynamic symbol table
index. */
struct elf_link_hash_entry *low;
/* The least dynamic symbol table index corresponding to a non-TLS
symbol with a GOT entry. */
bfd_size_type min_got_dynindx;
/* The greatest dynamic symbol table index corresponding to a symbol
with a GOT entry that is not referenced (e.g., a dynamic symbol
with dynamic relocations pointing to it from non-primary GOTs). */
bfd_size_type max_unref_got_dynindx;
/* The greatest dynamic symbol table index corresponding to a local
symbol. */
bfd_size_type max_local_dynindx;
/* The greatest dynamic symbol table index corresponding to an external
symbol without a GOT entry. */
bfd_size_type max_non_got_dynindx;
/* If non-NULL, output BFD for .MIPS.xhash finalization. */
bfd *output_bfd;
/* If non-NULL, pointer to contents of .MIPS.xhash for filling in
real final dynindx. */
bfd_byte *mipsxhash;
};
/* We make up to two PLT entries if needed, one for standard MIPS code
and one for compressed code, either a MIPS16 or microMIPS one. We
keep a separate record of traditional lazy-binding stubs, for easier
processing. */
struct plt_entry
{
/* Traditional SVR4 stub offset, or -1 if none. */
bfd_vma stub_offset;
/* Standard PLT entry offset, or -1 if none. */
bfd_vma mips_offset;
/* Compressed PLT entry offset, or -1 if none. */
bfd_vma comp_offset;
/* The corresponding .got.plt index, or -1 if none. */
bfd_vma gotplt_index;
/* Whether we need a standard PLT entry. */
unsigned int need_mips : 1;
/* Whether we need a compressed PLT entry. */
unsigned int need_comp : 1;
};
/* The MIPS ELF linker needs additional information for each symbol in
the global hash table. */
struct mips_elf_link_hash_entry
{
struct elf_link_hash_entry root;
/* External symbol information. */
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
this symbol. */
unsigned int possibly_dynamic_relocs;
/* 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. */
asection *fn_stub;
/* 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. */
asection *call_stub;
/* This is like the call_stub field, but it is used if the function
being called returns a floating point value. */
asection *call_fp_stub;
/* If non-zero, location in .MIPS.xhash to write real final dynindx. */
bfd_vma mipsxhash_loc;
/* The highest GGA_* value that satisfies all references to this symbol. */
unsigned int global_got_area : 2;
/* True if all GOT relocations against this symbol are for calls. This is
a looser condition than no_fn_stub below, because there may be other
non-call non-GOT relocations against the symbol. */
unsigned int got_only_for_calls : 1;
/* 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;
/* Does this symbol resolve to a PLT entry? */
unsigned int use_plt_entry : 1;
};
/* MIPS ELF linker hash table. */
struct mips_elf_link_hash_table
{
struct elf_link_hash_table root;
/* The number of .rtproc entries. */
bfd_size_type procedure_count;
/* The size of the .compact_rel section (if SGI_COMPAT). */
bfd_size_type compact_rel_size;
/* 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 and IRIX6. */
bool use_rld_obj_head;
/* The __rld_map or __rld_obj_head symbol. */
struct elf_link_hash_entry *rld_symbol;
/* This is set if we see any mips16 stub sections. */
bool mips16_stubs_seen;
/* True if we can generate copy relocs and PLTs. */
bool use_plts_and_copy_relocs;
/* True if we can only use 32-bit microMIPS instructions. */
bool insn32;
/* True if we suppress checks for invalid branches between ISA modes. */
bool ignore_branch_isa;
/* True if we are targetting R6 compact branches. */
bool compact_branches;
/* True if we already reported the small-data section overflow. */
bool small_data_overflow_reported;
/* True if we use the special `__gnu_absolute_zero' symbol. */
bool use_absolute_zero;
/* True if we have been configured for a GNU target. */
bool gnu_target;
/* Shortcuts to some dynamic sections, or NULL if they are not
being used. */
asection *srelplt2;
asection *sstubs;
/* The master GOT information. */
struct mips_got_info *got_info;
/* The global symbol in the GOT with the lowest index in the dynamic
symbol table. */
struct elf_link_hash_entry *global_gotsym;
/* The size of the PLT header in bytes. */
bfd_vma plt_header_size;
/* The size of a standard PLT entry in bytes. */
bfd_vma plt_mips_entry_size;
/* The size of a compressed PLT entry in bytes. */
bfd_vma plt_comp_entry_size;
/* The offset of the next standard PLT entry to create. */
bfd_vma plt_mips_offset;
/* The offset of the next compressed PLT entry to create. */
bfd_vma plt_comp_offset;
/* The index of the next .got.plt entry to create. */
bfd_vma plt_got_index;
/* The number of functions that need a lazy-binding stub. */
bfd_vma lazy_stub_count;
/* The size of a function stub entry in bytes. */
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 *);
/* Is the PLT header compressed? */
unsigned int plt_header_is_comp : 1;
};
/* Get the MIPS ELF linker hash table from a link_info structure. */
#define mips_elf_hash_table(p) \
((is_elf_hash_table ((p)->hash) \
&& elf_hash_table_id (elf_hash_table (p)) == MIPS_ELF_DATA) \
? (struct mips_elf_link_hash_table *) (p)->hash : NULL)
/* 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. */
bool error;
};
/* Used to store a REL high-part relocation such as R_MIPS_HI16 or
R_MIPS_GOT16. REL is the relocation, INPUT_SECTION is the section
that contains the relocation field and DATA points to the start of
INPUT_SECTION. */
struct mips_hi16
{
struct mips_hi16 *next;
bfd_byte *data;
asection *input_section;
arelent rel;
};
/* MIPS ELF private object data. */
struct mips_elf_obj_tdata
{
/* Generic ELF private object data. */
struct elf_obj_tdata root;
/* Input BFD providing Tag_GNU_MIPS_ABI_FP attribute for output. */
bfd *abi_fp_bfd;
/* Input BFD providing Tag_GNU_MIPS_ABI_MSA attribute for output. */
bfd *abi_msa_bfd;
/* The abiflags for this object. */
Elf_Internal_ABIFlags_v0 abiflags;
bool abiflags_valid;
/* The GOT requirements of input bfds. */
struct mips_got_info *got;
/* Used by _bfd_mips_elf_find_nearest_line. The structure could be
included directly in this one, but there's no point to wasting
the memory just for the infrequently called find_nearest_line. */
struct mips_elf_find_line *find_line_info;
/* An array of stub sections indexed by symbol number. */
asection **local_stubs;
asection **local_call_stubs;
/* The Irix 5 support uses two virtual sections, which represent
text/data symbols defined in dynamic objects. */
asymbol *elf_data_symbol;
asymbol *elf_text_symbol;
asection *elf_data_section;
asection *elf_text_section;
struct mips_hi16 *mips_hi16_list;
};
/* Get MIPS ELF private object data from BFD's tdata. */
#define mips_elf_tdata(bfd) \
((struct mips_elf_obj_tdata *) (bfd)->tdata.any)
#define TLS_RELOC_P(r_type) \
(r_type == R_MIPS_TLS_DTPMOD32 \
|| r_type == R_MIPS_TLS_DTPMOD64 \
|| r_type == R_MIPS_TLS_DTPREL32 \
|| r_type == R_MIPS_TLS_DTPREL64 \
|| r_type == R_MIPS_TLS_GD \
|| r_type == R_MIPS_TLS_LDM \
|| r_type == R_MIPS_TLS_DTPREL_HI16 \
|| r_type == R_MIPS_TLS_DTPREL_LO16 \
|| r_type == R_MIPS_TLS_GOTTPREL \
|| r_type == R_MIPS_TLS_TPREL32 \
|| r_type == R_MIPS_TLS_TPREL64 \
|| r_type == R_MIPS_TLS_TPREL_HI16 \
|| r_type == R_MIPS_TLS_TPREL_LO16 \
|| r_type == R_MIPS16_TLS_GD \
|| r_type == R_MIPS16_TLS_LDM \
|| r_type == R_MIPS16_TLS_DTPREL_HI16 \
|| r_type == R_MIPS16_TLS_DTPREL_LO16 \
|| r_type == R_MIPS16_TLS_GOTTPREL \
|| r_type == R_MIPS16_TLS_TPREL_HI16 \
|| r_type == R_MIPS16_TLS_TPREL_LO16 \
|| r_type == R_MICROMIPS_TLS_GD \
|| r_type == R_MICROMIPS_TLS_LDM \
|| r_type == R_MICROMIPS_TLS_DTPREL_HI16 \
|| r_type == R_MICROMIPS_TLS_DTPREL_LO16 \
|| r_type == R_MICROMIPS_TLS_GOTTPREL \
|| r_type == R_MICROMIPS_TLS_TPREL_HI16 \
|| r_type == R_MICROMIPS_TLS_TPREL_LO16)
/* Structure used to pass information to mips_elf_output_extsym. */
struct extsym_info
{
bfd *abfd;
struct bfd_link_info *info;
struct ecoff_debug_info *debug;
const struct ecoff_debug_swap *swap;
bool failed;
};
/* The names of the runtime procedure table symbols used on IRIX5. */
static const char * const mips_elf_dynsym_rtproc_names[] =
{
"_procedure_table",
"_procedure_string_table",
"_procedure_table_size",
NULL
};
/* These structures are used to generate the .compact_rel section on
IRIX5. */
typedef struct
{
unsigned long id1; /* Always one? */
unsigned long num; /* Number of compact relocation entries. */
unsigned long id2; /* Always two? */
unsigned long offset; /* The file offset of the first relocation. */
unsigned long reserved0; /* Zero? */
unsigned long reserved1; /* Zero? */
} Elf32_compact_rel;
typedef struct
{
bfd_byte id1[4];
bfd_byte num[4];
bfd_byte id2[4];
bfd_byte offset[4];
bfd_byte reserved0[4];
bfd_byte reserved1[4];
} Elf32_External_compact_rel;
typedef struct
{
unsigned int ctype : 1; /* 1: long 0: short format. See below. */
unsigned int rtype : 4; /* Relocation types. See below. */
unsigned int dist2to : 8;
unsigned int relvaddr : 19; /* (VADDR - vaddr of the previous entry)/ 4 */
unsigned long konst; /* KONST field. See below. */
unsigned long vaddr; /* VADDR to be relocated. */
} Elf32_crinfo;
typedef struct
{
unsigned int ctype : 1; /* 1: long 0: short format. See below. */
unsigned int rtype : 4; /* Relocation types. See below. */
unsigned int dist2to : 8;
unsigned int relvaddr : 19; /* (VADDR - vaddr of the previous entry)/ 4 */
unsigned long konst; /* KONST field. See below. */
} Elf32_crinfo2;
typedef struct
{
bfd_byte info[4];
bfd_byte konst[4];
bfd_byte vaddr[4];
} Elf32_External_crinfo;
typedef struct
{
bfd_byte info[4];
bfd_byte konst[4];
} Elf32_External_crinfo2;
/* These are the constants used to swap the bitfields in a crinfo. */
#define CRINFO_CTYPE (0x1U)
#define CRINFO_CTYPE_SH (31)
#define CRINFO_RTYPE (0xfU)
#define CRINFO_RTYPE_SH (27)
#define CRINFO_DIST2TO (0xffU)
#define CRINFO_DIST2TO_SH (19)
#define CRINFO_RELVADDR (0x7ffffU)
#define CRINFO_RELVADDR_SH (0)
/* A compact relocation info has long (3 words) or short (2 words)
formats. A short format doesn't have VADDR field and relvaddr
fields contains ((VADDR - vaddr of the previous entry) >> 2). */
#define CRF_MIPS_LONG 1
#define CRF_MIPS_SHORT 0
/* There are 4 types of compact relocation at least. The value KONST
has different meaning for each type:
(type) (konst)
CT_MIPS_REL32 Address in data
CT_MIPS_WORD Address in word (XXX)
CT_MIPS_GPHI_LO GP - vaddr
CT_MIPS_JMPAD Address to jump
*/
#define CRT_MIPS_REL32 0xa
#define CRT_MIPS_WORD 0xb
#define CRT_MIPS_GPHI_LO 0xc
#define CRT_MIPS_JMPAD 0xd
#define mips_elf_set_cr_format(x,format) ((x).ctype = (format))
#define mips_elf_set_cr_type(x,type) ((x).rtype = (type))
#define mips_elf_set_cr_dist2to(x,v) ((x).dist2to = (v))
#define mips_elf_set_cr_relvaddr(x,d) ((x).relvaddr = (d)<<2)
/* The structure of the runtime procedure descriptor created by the
loader for use by the static exception system. */
typedef struct runtime_pdr {
bfd_vma adr; /* Memory address of start of procedure. */
long regmask; /* Save register mask. */
long regoffset; /* Save register offset. */
long fregmask; /* Save floating point register mask. */
long fregoffset; /* Save floating point register offset. */
long frameoffset; /* Frame size. */
short framereg; /* Frame pointer register. */
short pcreg; /* Offset or reg of return pc. */
long irpss; /* Index into the runtime string table. */
long reserved;
struct exception_info *exception_info;/* Pointer to exception array. */
} RPDR, *pRPDR;
#define cbRPDR sizeof (RPDR)
#define rpdNil ((pRPDR) 0)
static struct mips_got_entry *mips_elf_create_local_got_entry
(bfd *, struct bfd_link_info *, bfd *, bfd_vma, unsigned long,
struct mips_elf_link_hash_entry *, int);
static bool mips_elf_sort_hash_table_f
(struct mips_elf_link_hash_entry *, void *);
static bfd_vma mips_elf_high
(bfd_vma);
static bool mips_elf_create_dynamic_relocation
(bfd *, struct bfd_link_info *, const Elf_Internal_Rela *,
struct mips_elf_link_hash_entry *, asection *, bfd_vma,
bfd_vma *, asection *);
static bfd_vma mips_elf_adjust_gp
(bfd *, struct mips_got_info *, bfd *);
/* This will be used when we sort the dynamic relocation records. */
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) != EF_MIPS_ARCH_1) \
|| ((elf_elfheader (abfd)->e_flags & EF_MIPS_MACH) == EF_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) == EF_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 for CPUs that are faster if JR is converted to B.
This should be safe for all architectures. We enable this predicate for
all CPUs. */
#define JR_TO_B_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 O32 ABI. */
#define ABI_O32_P(abfd) \
((elf_elfheader (abfd)->e_flags & EF_MIPS_ABI) == EF_MIPS_ABI_O32)
/* Nonzero if ABFD is using the N32 ABI. */
#define ABI_N32_P(abfd) \
((elf_elfheader (abfd)->e_flags & EF_MIPS_ABI2) != 0)
/* Nonzero if ABFD is using the N64 ABI. */
#define ABI_64_P(abfd) \
(get_elf_backend_data (abfd)->s->elfclass == ELFCLASS64)
/* Nonzero if ABFD is using NewABI conventions. */
#define NEWABI_P(abfd) (ABI_N32_P (abfd) || ABI_64_P (abfd))
/* Nonzero if ABFD has microMIPS code. */
#define MICROMIPS_P(abfd) \
((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_MICROMIPS) != 0)
/* Nonzero if ABFD is MIPS R6. */
#define MIPSR6_P(abfd) \
((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_32R6 \
|| (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_64R6)
/* The IRIX compatibility level we are striving for. */
#define IRIX_COMPAT(abfd) \
(get_elf_backend_data (abfd)->elf_backend_mips_irix_compat (abfd))
/* Whether we are trying to be compatible with IRIX at all. */
#define SGI_COMPAT(abfd) \
(IRIX_COMPAT (abfd) != ict_none)
/* The name of the options section. */
#define MIPS_ELF_OPTIONS_SECTION_NAME(abfd) \
(NEWABI_P (abfd) ? ".MIPS.options" : ".options")
/* True if NAME is the recognized name of any SHT_MIPS_OPTIONS section.
Some IRIX system files do not use MIPS_ELF_OPTIONS_SECTION_NAME. */
#define MIPS_ELF_OPTIONS_SECTION_NAME_P(NAME) \
(strcmp (NAME, ".MIPS.options") == 0 || strcmp (NAME, ".options") == 0)
/* True if NAME is the recognized name of any SHT_MIPS_ABIFLAGS section. */
#define MIPS_ELF_ABIFLAGS_SECTION_NAME_P(NAME) \
(strcmp (NAME, ".MIPS.abiflags") == 0)
/* Whether the section is readonly. */
#define MIPS_ELF_READONLY_SECTION(sec) \
((sec->flags & (SEC_ALLOC | SEC_LOAD | SEC_READONLY)) \
== (SEC_ALLOC | SEC_LOAD | SEC_READONLY))
/* The name of the stub section. */
#define MIPS_ELF_STUB_SECTION_NAME(abfd) ".MIPS.stubs"
/* The size of an external REL relocation. */
#define MIPS_ELF_REL_SIZE(abfd) \
(get_elf_backend_data (abfd)->s->sizeof_rel)
/* The size of an external RELA relocation. */
#define MIPS_ELF_RELA_SIZE(abfd) \
(get_elf_backend_data (abfd)->s->sizeof_rela)
/* The size of an external dynamic table entry. */
#define MIPS_ELF_DYN_SIZE(abfd) \
(get_elf_backend_data (abfd)->s->sizeof_dyn)
/* The size of a GOT entry. */
#define MIPS_ELF_GOT_SIZE(abfd) \
(get_elf_backend_data (abfd)->s->arch_size / 8)
/* The size of the .rld_map section. */
#define MIPS_ELF_RLD_MAP_SIZE(abfd) \
(get_elf_backend_data (abfd)->s->arch_size / 8)
/* The size of a symbol-table entry. */
#define MIPS_ELF_SYM_SIZE(abfd) \
(get_elf_backend_data (abfd)->s->sizeof_sym)
/* The default alignment for sections, as a power of two. */
#define MIPS_ELF_LOG_FILE_ALIGN(abfd) \
(get_elf_backend_data (abfd)->s->log_file_align)
/* Get word-sized data. */
#define MIPS_ELF_GET_WORD(abfd, ptr) \
(ABI_64_P (abfd) ? bfd_get_64 (abfd, ptr) : bfd_get_32 (abfd, ptr))
/* Put out word-sized data. */
#define MIPS_ELF_PUT_WORD(abfd, val, ptr) \
(ABI_64_P (abfd) \
? bfd_put_64 (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. */
#define MIPS_ELF_ADD_DYNAMIC_ENTRY(info, tag, val) \
_bfd_elf_add_dynamic_entry (info, tag, val)
#define MIPS_ELF_RTYPE_TO_HOWTO(abfd, rtype, rela) \
(get_elf_backend_data (abfd)->elf_backend_mips_rtype_to_howto (abfd, rtype, rela))
/* The name of the dynamic relocation section. */
#define MIPS_ELF_REL_DYN_NAME(INFO) \
(mips_elf_hash_table (INFO)->root.target_os == is_vxworks \
? ".rela.dyn" : ".rel.dyn")
/* In case we're on a 32-bit machine, construct a 64-bit "-1" value
from smaller values. Start with zero, widen, *then* decrement. */
#define MINUS_ONE (((bfd_vma)0) - 1)
#define MINUS_TWO (((bfd_vma)0) - 2)
/* The value to write into got[1] for SVR4 targets, to identify it is
a GNU object. The dynamic linker can then use got[1] to store the
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. */
#define ELF_MIPS_GP_OFFSET(INFO) \
(mips_elf_hash_table (INFO)->root.target_os == is_vxworks \
? 0x0 : 0x7ff0)
/* The maximum size of the GOT for it to be addressable using 16-bit
offsets from $gp. */
#define MIPS_ELF_GOT_MAX_SIZE(INFO) (ELF_MIPS_GP_OFFSET (INFO) + 0x7fff)
/* Instructions which appear in a stub. */
#define STUB_LW(abfd) \
((ABI_64_P (abfd) \
? 0xdf998010 /* ld t9,0x8010(gp) */ \
: 0x8f998010)) /* lw t9,0x8010(gp) */
#define STUB_MOVE 0x03e07825 /* or t7,ra,zero */
#define STUB_LUI(VAL) (0x3c180000 + (VAL)) /* lui t8,VAL */
#define STUB_JALR 0x0320f809 /* jalr ra,t9 */
#define STUB_JALRC 0xf8190000 /* jalrc ra,t9 */
#define STUB_ORI(VAL) (0x37180000 + (VAL)) /* ori t8,t8,VAL */
#define STUB_LI16U(VAL) (0x34180000 + (VAL)) /* ori t8,zero,VAL unsigned */
#define STUB_LI16S(abfd, VAL) \
((ABI_64_P (abfd) \
? (0x64180000 + (VAL)) /* daddiu t8,zero,VAL sign extended */ \
: (0x24180000 + (VAL)))) /* addiu t8,zero,VAL sign extended */
/* Likewise for the microMIPS ASE. */
#define STUB_LW_MICROMIPS(abfd) \
(ABI_64_P (abfd) \
? 0xdf3c8010 /* ld t9,0x8010(gp) */ \
: 0xff3c8010) /* lw t9,0x8010(gp) */
#define STUB_MOVE_MICROMIPS 0x0dff /* move t7,ra */
#define STUB_MOVE32_MICROMIPS 0x001f7a90 /* or t7,ra,zero */
#define STUB_LUI_MICROMIPS(VAL) \
(0x41b80000 + (VAL)) /* lui t8,VAL */
#define STUB_JALR_MICROMIPS 0x45d9 /* jalr t9 */
#define STUB_JALR32_MICROMIPS 0x03f90f3c /* jalr ra,t9 */
#define STUB_ORI_MICROMIPS(VAL) \
(0x53180000 + (VAL)) /* ori t8,t8,VAL */
#define STUB_LI16U_MICROMIPS(VAL) \
(0x53000000 + (VAL)) /* ori t8,zero,VAL unsigned */
#define STUB_LI16S_MICROMIPS(abfd, VAL) \
(ABI_64_P (abfd) \
? 0x5f000000 + (VAL) /* daddiu t8,zero,VAL sign extended */ \
: 0x33000000 + (VAL)) /* addiu t8,zero,VAL sign extended */
#define MIPS_FUNCTION_STUB_NORMAL_SIZE 16
#define MIPS_FUNCTION_STUB_BIG_SIZE 20
#define MICROMIPS_FUNCTION_STUB_NORMAL_SIZE 12
#define MICROMIPS_FUNCTION_STUB_BIG_SIZE 16
#define MICROMIPS_INSN32_FUNCTION_STUB_NORMAL_SIZE 16
#define MICROMIPS_INSN32_FUNCTION_STUB_BIG_SIZE 20
/* The name of the dynamic interpreter. This is put in the .interp
section. */
#define ELF_DYNAMIC_INTERPRETER(abfd) \
(ABI_N32_P (abfd) ? "/usr/lib32/libc.so.1" \
: ABI_64_P (abfd) ? "/usr/lib64/libc.so.1" \
: "/usr/lib/libc.so.1")
#ifdef BFD64
#define MNAME(bfd,pre,pos) \
(ABI_64_P (bfd) ? CONCAT4 (pre,64,_,pos) : CONCAT4 (pre,32,_,pos))
#define ELF_R_SYM(bfd, i) \
(ABI_64_P (bfd) ? ELF64_R_SYM (i) : ELF32_R_SYM (i))
#define ELF_R_TYPE(bfd, i) \
(ABI_64_P (bfd) ? ELF64_MIPS_R_TYPE (i) : ELF32_R_TYPE (i))
#define ELF_R_INFO(bfd, s, t) \
(ABI_64_P (bfd) ? ELF64_R_INFO (s, t) : ELF32_R_INFO (s, t))
#else
#define MNAME(bfd,pre,pos) CONCAT4 (pre,32,_,pos)
#define ELF_R_SYM(bfd, i) \
(ELF32_R_SYM (i))
#define ELF_R_TYPE(bfd, i) \
(ELF32_R_TYPE (i))
#define ELF_R_INFO(bfd, s, t) \
(ELF32_R_INFO (s, t))
#endif
/* The mips16 compiler uses a couple of special sections to handle
floating point arguments.
Section names that look like .mips16.fn.FNNAME contain stubs that
copy floating point arguments from the fp regs to the gp regs and
then jump to FNNAME. If any 32 bit function calls FNNAME, the
call should be redirected to the stub instead. If no 32 bit
function calls FNNAME, the stub should be discarded. We need to
consider any reference to the function, not just a call, because
if the address of the function is taken we will need the stub,
since the address might be passed to a 32 bit function.
Section names that look like .mips16.call.FNNAME contain stubs
that copy floating point arguments from the gp regs to the fp
regs and then jump to FNNAME. If FNNAME is a 32 bit function,
then any 16 bit function that calls FNNAME should be redirected
to the stub instead. If FNNAME is not a 32 bit function, the
stub should be discarded.
.mips16.call.fp.FNNAME sections are similar, but contain stubs
which call FNNAME and then copy the return value from the fp regs
to the gp regs. These stubs store the return value in $18 while
calling FNNAME; any function which might call one of these stubs
must arrange to save $18 around the call. (This case is not
needed for 32 bit functions that call 16 bit functions, because
16 bit functions always return floating point values in both
$f0/$f1 and $2/$3.)
Note that in all cases FNNAME might be defined statically.
Therefore, FNNAME is not used literally. Instead, the relocation
information will indicate which symbol the section is for.
We record any stubs that we find in the symbol table. */
#define FN_STUB ".mips16.fn."
#define CALL_STUB ".mips16.call."
#define CALL_FP_STUB ".mips16.call.fp."
#define FN_STUB_P(name) startswith (name, FN_STUB)
#define CALL_STUB_P(name) startswith (name, CALL_STUB)
#define CALL_FP_STUB_P(name) startswith (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 */
0x03e07825, /* or t7, ra, zero */
0x0018c082, /* srl $24, $24, 2 */
0x0320f809, /* jalr $25 */
0x2718fffe /* subu $24, $24, 2 */
};
/* The format of the first PLT entry in an O32 executable using compact
jumps. */
static const bfd_vma mipsr6_o32_exec_plt0_entry_compact[] =
{
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 # 32-bit move (addu) */
0x0018c082, /* srl $24, $24, 2 */
0x2718fffe, /* subu $24, $24, 2 */
0xf8190000 /* jalrc $25 */
};
/* 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 */
0x03e07825, /* or t7, ra, zero */
0x0018c082, /* srl $24, $24, 2 */
0x0320f809, /* jalr $25 */
0x2718fffe /* subu $24, $24, 2 */
};
/* The format of the first PLT entry in an N32 executable using compact
jumps. Different because gp ($28) is not available; we use t2 ($14)
instead. */
static const bfd_vma mipsr6_n32_exec_plt0_entry_compact[] =
{
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 # 32-bit move (addu) */
0x0018c082, /* srl $24, $24, 2 */
0x2718fffe, /* subu $24, $24, 2 */
0xf8190000 /* jalrc $25 */
};
/* 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 */
0x03e07825, /* or t7, ra, zero */
0x0018c0c2, /* srl $24, $24, 3 */
0x0320f809, /* jalr $25 */
0x2718fffe /* subu $24, $24, 2 */
};
/* The format of the first PLT entry in an N64 executable using compact
jumps. Different from N32 because of the increased size of GOT
entries. */
static const bfd_vma mipsr6_n64_exec_plt0_entry_compact[] =
{
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 */
0x03e0782d, /* move $15, $31 # 64-bit move (daddu) */
0x0018c0c2, /* srl $24, $24, 3 */
0x2718fffe, /* subu $24, $24, 2 */
0xf8190000 /* jalrc $25 */
};
/* The format of the microMIPS first PLT entry in an O32 executable.
We rely on v0 ($2) rather than t8 ($24) to contain the address
of the GOTPLT entry handled, so this stub may only be used when
all the subsequent PLT entries are microMIPS code too.
The trailing NOP is for alignment and correct disassembly only. */
static const bfd_vma micromips_o32_exec_plt0_entry[] =
{
0x7980, 0x0000, /* addiupc $3, (&GOTPLT[0]) - . */
0xff23, 0x0000, /* lw $25, 0($3) */
0x0535, /* subu $2, $2, $3 */
0x2525, /* srl $2, $2, 2 */
0x3302, 0xfffe, /* subu $24, $2, 2 */
0x0dff, /* move $15, $31 */
0x45f9, /* jalrs $25 */
0x0f83, /* move $28, $3 */
0x0c00 /* nop */
};
/* The format of the microMIPS first PLT entry in an O32 executable
in the insn32 mode. */
static const bfd_vma micromips_insn32_o32_exec_plt0_entry[] =
{
0x41bc, 0x0000, /* lui $28, %hi(&GOTPLT[0]) */
0xff3c, 0x0000, /* lw $25, %lo(&GOTPLT[0])($28) */
0x339c, 0x0000, /* addiu $28, $28, %lo(&GOTPLT[0]) */
0x0398, 0xc1d0, /* subu $24, $24, $28 */
0x001f, 0x7a90, /* or $15, $31, zero */
0x0318, 0x1040, /* srl $24, $24, 2 */
0x03f9, 0x0f3c, /* jalr $25 */
0x3318, 0xfffe /* subu $24, $24, 2 */
};
/* The format of subsequent standard 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 */
};
static const bfd_vma mipsr6_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) */
0x03200009 /* jr $25 */
};
static const bfd_vma mipsr6_exec_plt_entry_compact[] =
{
0x3c0f0000, /* lui $15, %hi(.got.plt entry) */
0x01f90000, /* l[wd] $25, %lo(.got.plt entry)($15) */
0x25f80000, /* addiu $24, $15, %lo(.got.plt entry) */
0xd8190000 /* jic $25, 0 */
};
/* The format of subsequent MIPS16 o32 PLT entries. We use v0 ($2)
and v1 ($3) as temporaries because t8 ($24) and t9 ($25) are not
directly addressable. */
static const bfd_vma mips16_o32_exec_plt_entry[] =
{
0xb203, /* lw $2, 12($pc) */
0x9a60, /* lw $3, 0($2) */
0x651a, /* move $24, $2 */
0xeb00, /* jr $3 */
0x653b, /* move $25, $3 */
0x6500, /* nop */
0x0000, 0x0000 /* .word (.got.plt entry) */
};
/* The format of subsequent microMIPS o32 PLT entries. We use v0 ($2)
as a temporary because t8 ($24) is not addressable with ADDIUPC. */
static const bfd_vma micromips_o32_exec_plt_entry[] =
{
0x7900, 0x0000, /* addiupc $2, (.got.plt entry) - . */
0xff22, 0x0000, /* lw $25, 0($2) */
0x4599, /* jr $25 */
0x0f02 /* move $24, $2 */
};
/* The format of subsequent microMIPS o32 PLT entries in the insn32 mode. */
static const bfd_vma micromips_insn32_o32_exec_plt_entry[] =
{
0x41af, 0x0000, /* lui $15, %hi(.got.plt entry) */
0xff2f, 0x0000, /* lw $25, %lo(.got.plt entry)($15) */
0x0019, 0x0f3c, /* jr $25 */
0x330f, 0x0000 /* addiu $24, $15, %lo(.got.plt entry) */
};
/* The format of the first PLT entry in a VxWorks executable. */
static const bfd_vma mips_vxworks_exec_plt0_entry[] =
{
0x3c190000, /* lui t9, %hi(_GLOBAL_OFFSET_TABLE_) */
0x27390000, /* addiu t9, t9, %lo(_GLOBAL_OFFSET_TABLE_) */
0x8f390008, /* lw t9, 8(t9) */
0x00000000, /* nop */
0x03200008, /* jr t9 */
0x00000000 /* nop */
};
/* The format of subsequent PLT entries. */
static const bfd_vma mips_vxworks_exec_plt_entry[] =
{
0x10000000, /* b .PLT_resolver */
0x24180000, /* li t8, <pltindex> */
0x3c190000, /* lui t9, %hi(<.got.plt slot>) */
0x27390000, /* addiu t9, t9, %lo(<.got.plt slot>) */
0x8f390000, /* lw t9, 0(t9) */
0x00000000, /* nop */
0x03200008, /* jr t9 */
0x00000000 /* nop */
};
/* The format of the first PLT entry in a VxWorks shared object. */
static const bfd_vma mips_vxworks_shared_plt0_entry[] =
{
0x8f990008, /* lw t9, 8(gp) */
0x00000000, /* nop */
0x03200008, /* jr t9 */
0x00000000, /* nop */
0x00000000, /* nop */
0x00000000 /* nop */
};
/* The format of subsequent PLT entries. */
static const bfd_vma mips_vxworks_shared_plt_entry[] =
{
0x10000000, /* b .PLT_resolver */
0x24180000 /* li t8, <pltindex> */
};
/* microMIPS 32-bit opcode helper installer. */
static void
bfd_put_micromips_32 (const bfd *abfd, bfd_vma opcode, bfd_byte *ptr)
{
bfd_put_16 (abfd, (opcode >> 16) & 0xffff, ptr);
bfd_put_16 (abfd, opcode & 0xffff, ptr + 2);
}
/* microMIPS 32-bit opcode helper retriever. */
static bfd_vma
bfd_get_micromips_32 (const bfd *abfd, const bfd_byte *ptr)
{
return (bfd_get_16 (abfd, ptr) << 16) | bfd_get_16 (abfd, ptr + 2);
}
/* Look up an entry in a MIPS ELF linker hash table. */
#define mips_elf_link_hash_lookup(table, string, create, copy, follow) \
((struct mips_elf_link_hash_entry *) \
elf_link_hash_lookup (&(table)->root, (string), (create), \
(copy), (follow)))
/* Traverse a MIPS ELF linker hash table. */
#define mips_elf_link_hash_traverse(table, func, info) \
(elf_link_hash_traverse \
(&(table)->root, \
(bool (*) (struct elf_link_hash_entry *, void *)) (func), \
(info)))
/* Find the base offsets for thread-local storage in this object,
for GD/LD and IE/LE respectively. */
#define TP_OFFSET 0x7000
#define DTP_OFFSET 0x8000
static bfd_vma
dtprel_base (struct bfd_link_info *info)
{
/* If tls_sec is NULL, we should have signalled an error already. */
if (elf_hash_table (info)->tls_sec == NULL)
return 0;
return elf_hash_table (info)->tls_sec->vma + DTP_OFFSET;
}
static bfd_vma
tprel_base (struct bfd_link_info *info)
{
/* If tls_sec is NULL, we should have signalled an error already. */
if (elf_hash_table (info)->tls_sec == NULL)
return 0;
return elf_hash_table (info)->tls_sec->vma + TP_OFFSET;
}
/* Create an entry in a MIPS ELF linker hash table. */
static struct bfd_hash_entry *
mips_elf_link_hash_newfunc (struct bfd_hash_entry *entry,
struct bfd_hash_table *table, const char *string)
{
struct mips_elf_link_hash_entry *ret =
(struct mips_elf_link_hash_entry *) entry;
/* Allocate the structure if it has not already been allocated by a
subclass. */
if (ret == NULL)
ret = bfd_hash_allocate (table, sizeof (struct mips_elf_link_hash_entry));
if (ret == NULL)
return (struct bfd_hash_entry *) ret;
/* Call the allocation method of the superclass. */
ret = ((struct mips_elf_link_hash_entry *)
_bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret,
table, string));
if (ret != NULL)
{
/* Set local fields. */
memset (&ret->esym, 0, sizeof (EXTR));
/* We use -2 as a marker to indicate that the information has
not been set. -1 means there is no associated ifd. */
ret->esym.ifd = -2;
ret->la25_stub = 0;
ret->possibly_dynamic_relocs = 0;
ret->fn_stub = NULL;
ret->call_stub = NULL;
ret->call_fp_stub = NULL;
ret->mipsxhash_loc = 0;
ret->global_got_area = GGA_NONE;
ret->got_only_for_calls = true;
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;
ret->use_plt_entry = false;
}
return (struct bfd_hash_entry *) ret;
}
/* Allocate MIPS ELF private object data. */
bool
_bfd_mips_elf_mkobject (bfd *abfd)
{
return bfd_elf_allocate_object (abfd, sizeof (struct mips_elf_obj_tdata),
MIPS_ELF_DATA);
}
/* MIPS ELF uses a special find_nearest_line routine in order the
handle the ECOFF debugging information. */
struct mips_elf_find_line
{
struct ecoff_debug_info d;
struct ecoff_find_line i;
};
bool
_bfd_mips_elf_free_cached_info (bfd *abfd)
{
struct mips_elf_obj_tdata *tdata;
if ((bfd_get_format (abfd) == bfd_object
|| bfd_get_format (abfd) == bfd_core)
&& (tdata = mips_elf_tdata (abfd)) != NULL)
{
BFD_ASSERT (tdata->root.object_id == MIPS_ELF_DATA);
while (tdata->mips_hi16_list != NULL)
{
struct mips_hi16 *hi = tdata->mips_hi16_list;
tdata->mips_hi16_list = hi->next;
free (hi);
}
if (tdata->find_line_info != NULL)
_bfd_ecoff_free_ecoff_debug_info (&tdata->find_line_info->d);
}
return _bfd_elf_free_cached_info (abfd);
}
bool
_bfd_mips_elf_new_section_hook (bfd *abfd, asection *sec)
{
if (!sec->used_by_bfd)
{
struct _mips_elf_section_data *sdata;
size_t amt = sizeof (*sdata);
sdata = bfd_zalloc (abfd, amt);
if (sdata == NULL)
return false;
sec->used_by_bfd = sdata;
}
return _bfd_elf_new_section_hook (abfd, sec);
}
/* Read ECOFF debugging information from a .mdebug section into a
ecoff_debug_info structure. */
bool
_bfd_mips_elf_read_ecoff_info (bfd *abfd, asection *section,
struct ecoff_debug_info *debug)
{
HDRR *symhdr;
const struct ecoff_debug_swap *swap;
char *ext_hdr;
swap = get_elf_backend_data (abfd)->elf_backend_ecoff_debug_swap;
memset (debug, 0, sizeof (*debug));
ext_hdr = bfd_malloc (swap->external_hdr_size);
if (ext_hdr == NULL && swap->external_hdr_size != 0)
goto error_return;
if (! bfd_get_section_contents (abfd, section, ext_hdr, 0,
swap->external_hdr_size))
goto error_return;
symhdr = &debug->symbolic_header;
(*swap->swap_hdr_in) (abfd, ext_hdr, symhdr);
free (ext_hdr);
ext_hdr = NULL;
/* The symbolic header contains absolute file offsets and sizes to
read. */
#define READ(ptr, offset, count, size) \
do \
{ \
size_t amt; \
debug->ptr = NULL; \
if (symhdr->count == 0) \
break; \
if (_bfd_mul_overflow (size, symhdr->count, &amt)) \
{ \
bfd_set_error (bfd_error_file_too_big); \
goto error_return; \
} \
if (bfd_seek (abfd, symhdr->offset, SEEK_SET) != 0) \
goto error_return; \
debug->ptr = _bfd_malloc_and_read (abfd, amt + 1, amt); \
if (debug->ptr == NULL) \
goto error_return; \
((char *) debug->ptr)[amt] = 0; \
} while (0)
READ (line, cbLineOffset, cbLine, sizeof (unsigned char));
READ (external_dnr, cbDnOffset, idnMax, swap->external_dnr_size);
READ (external_pdr, cbPdOffset, ipdMax, swap->external_pdr_size);
READ (external_sym, cbSymOffset, isymMax, swap->external_sym_size);
READ (external_opt, cbOptOffset, ioptMax, swap->external_opt_size);
READ (external_aux, cbAuxOffset, iauxMax, sizeof (union aux_ext));
READ (ss, cbSsOffset, issMax, sizeof (char));
READ (ssext, cbSsExtOffset, issExtMax, sizeof (char));
READ (external_fdr, cbFdOffset, ifdMax, swap->external_fdr_size);
READ (external_rfd, cbRfdOffset, crfd, swap->external_rfd_size);
READ (external_ext, cbExtOffset, iextMax, swap->external_ext_size);
#undef READ
return true;
error_return:
free (ext_hdr);
_bfd_ecoff_free_ecoff_debug_info (debug);
return false;
}
/* Swap RPDR (runtime procedure table entry) for output. */
static void
ecoff_swap_rpdr_out (bfd *abfd, const RPDR *in, struct rpdr_ext *ex)
{
H_PUT_S32 (abfd, in->adr, ex->p_adr);
H_PUT_32 (abfd, in->regmask, ex->p_regmask);
H_PUT_32 (abfd, in->regoffset, ex->p_regoffset);
H_PUT_32 (abfd, in->fregmask, ex->p_fregmask);
H_PUT_32 (abfd, in->fregoffset, ex->p_fregoffset);
H_PUT_32 (abfd, in->frameoffset, ex->p_frameoffset);
H_PUT_16 (abfd, in->framereg, ex->p_framereg);
H_PUT_16 (abfd, in->pcreg, ex->p_pcreg);
H_PUT_32 (abfd, in->irpss, ex->p_irpss);
}
/* Create a runtime procedure table from the .mdebug section. */
static bool
mips_elf_create_procedure_table (void *handle, bfd *abfd,
struct bfd_link_info *info, asection *s,
struct ecoff_debug_info *debug)
{
const struct ecoff_debug_swap *swap;
HDRR *hdr = &debug->symbolic_header;
RPDR *rpdr, *rp;
struct rpdr_ext *erp;
void *rtproc;
struct pdr_ext *epdr;
struct sym_ext *esym;
char *ss, **sv;
char *str;
bfd_size_type size;
bfd_size_type count;
unsigned long sindex;
unsigned long i;
PDR pdr;
SYMR sym;
const char *no_name_func = _("static procedure (no name)");
epdr = NULL;
rpdr = NULL;
esym = NULL;
ss = NULL;
sv = NULL;
swap = get_elf_backend_data (abfd)->elf_backend_ecoff_debug_swap;
sindex = strlen (no_name_func) + 1;
count = hdr->ipdMax;
if (count > 0)
{
size = swap->external_pdr_size;
epdr = bfd_malloc (size * count);
if (epdr == NULL)
goto error_return;
if (! _bfd_ecoff_get_accumulated_pdr (handle, (bfd_byte *) epdr))
goto error_return;
size = sizeof (RPDR);
rp = rpdr = bfd_malloc (size * count);
if (rpdr == NULL)
goto error_return;
size = sizeof (char *);
sv = bfd_malloc (size * count);
if (sv == NULL)
goto error_return;
count = hdr->isymMax;
size = swap->external_sym_size;
esym = bfd_malloc (size * count);
if (esym == NULL)
goto error_return;
if (! _bfd_ecoff_get_accumulated_sym (handle, (bfd_byte *) esym))
goto error_return;
count = hdr->issMax;
ss = bfd_malloc (count);
if (ss == NULL)
goto error_return;
if (! _bfd_ecoff_get_accumulated_ss (handle, (bfd_byte *) ss))
goto error_return;
count = hdr->ipdMax;
for (i = 0; i < (unsigned long) count; i++, rp++)
{
(*swap->swap_pdr_in) (abfd, epdr + i, &pdr);
(*swap->swap_sym_in) (abfd, &esym[pdr.isym], &sym);
rp->adr = sym.value;
rp->regmask = pdr.regmask;
rp->regoffset = pdr.regoffset;
rp->fregmask = pdr.fregmask;
rp->fregoffset = pdr.fregoffset;
rp->frameoffset = pdr.frameoffset;
rp->framereg = pdr.framereg;
rp->pcreg = pdr.pcreg;
rp->irpss = sindex;
sv[i] = ss + sym.iss;
sindex += strlen (sv[i]) + 1;
}
}
size = sizeof (struct rpdr_ext) * (count + 2) + sindex;
size = BFD_ALIGN (size, 16);
rtproc = bfd_alloc (abfd, size);
if (rtproc == NULL)
{
mips_elf_hash_table (info)->procedure_count = 0;
goto error_return;
}
mips_elf_hash_table (info)->procedure_count = count + 2;
erp = rtproc;
memset (erp, 0, sizeof (struct rpdr_ext));
erp++;
str = (char *) rtproc + sizeof (struct rpdr_ext) * (count + 2);
strcpy (str, no_name_func);
str += strlen (no_name_func) + 1;
for (i = 0; i < count; i++)
{
ecoff_swap_rpdr_out (abfd, rpdr + i, erp + i);
strcpy (str, sv[i]);
str += strlen (sv[i]) + 1;
}
H_PUT_S32 (abfd, -1, (erp + count)->p_adr);
/* Set the size and contents of .rtproc section. */
s->size = size;
s->contents = rtproc;
/* Skip this section later on (I don't think this currently
matters, but someday it might). */
s->map_head.link_order = NULL;
free (epdr);
free (rpdr);
free (esym);
free (ss);
free (sv);
return true;
error_return:
free (epdr);
free (rpdr);
free (esym);
free (ss);
free (sv);
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 bool
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)
{
bool micromips_p = ELF_ST_IS_MICROMIPS (h->root.other);
struct bfd_link_hash_entry *bh;
struct elf_link_hash_entry *elfh;
char *name;
bool res;
if (micromips_p)
value |= 1;
/* Create a new symbol. */
name = concat (prefix, h->root.root.root.string, NULL);
bh = NULL;
res = _bfd_generic_link_add_one_symbol (info, s->owner, name,
BSF_LOCAL, s, value, NULL,
true, false, &bh);
free (name);
if (! res)
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;
if (micromips_p)
elfh->other = ELF_ST_SET_MICROMIPS (elfh->other);
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 bool
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;
char *name;
asection *s;
bfd_vma value;
bool res;
/* 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 = concat (prefix, h->root.root.root.string, NULL);
bh = NULL;
res = _bfd_generic_link_add_one_symbol (info, s->owner, name,
BSF_LOCAL, s, value, NULL,
true, false, &bh);
free (name);
if (! res)
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 bool
section_allows_mips16_refs_p (asection *section)
{
const char *name;
name = bfd_section_name (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 (const struct elf_backend_data *bed,
asection *sec ATTRIBUTE_UNUSED,
const Elf_Internal_Rela *relocs,
const Elf_Internal_Rela *relend)
{
int int_rels_per_ext_rel = bed->s->int_rels_per_ext_rel;
const Elf_Internal_Rela *rel;
/* Trust the first R_MIPS_NONE relocation, if any, but not a subsequent
one in a compound relocation. */
for (rel = relocs; rel < relend; rel += int_rels_per_ext_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
discard them. */
static void
mips_elf_check_mips16_stubs (struct bfd_link_info *info,
struct mips_elf_link_hash_entry *h)
{
/* Dynamic symbols must use the standard call interface, in case other
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
&& ! h->need_fn_stub)
{
/* We don't need the fn_stub; the only references to this symbol
are 16 bit calls. Clobber the size to 0 to prevent it from
being included in the link. */
h->fn_stub->size = 0;
h->fn_stub->flags &= ~SEC_RELOC;
h->fn_stub->reloc_count = 0;
h->fn_stub->flags |= SEC_EXCLUDE;
h->fn_stub->output_section = bfd_abs_section_ptr;
}
if (h->call_stub != NULL
&& ELF_ST_IS_MIPS16 (h->root.other))
{
/* 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
to 0 to prevent it from being included in the link. */
h->call_stub->size = 0;
h->call_stub->flags &= ~SEC_RELOC;
h->call_stub->reloc_count = 0;
h->call_stub->flags |= SEC_EXCLUDE;
h->call_stub->output_section = bfd_abs_section_ptr;
}
if (h->call_fp_stub != NULL
&& ELF_ST_IS_MIPS16 (h->root.other))
{
/* 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
to 0 to prevent it from being included in the link. */
h->call_fp_stub->size = 0;
h->call_fp_stub->flags &= ~SEC_RELOC;
h->call_fp_stub->reloc_count = 0;
h->call_fp_stub->flags |= SEC_EXCLUDE;
h->call_fp_stub->output_section = bfd_abs_section_ptr;
}
}
/* 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. */
bool
_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);
if (htab == NULL)
return false;
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 or its fn_stub might need $25 to be valid on entry.
Note that MIPS16 functions set up $gp using PC-relative instructions,
so they themselves never need $25 to be valid. Only non-MIPS16
entry points are of interest here. */
static bool
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)
&& !bfd_is_und_section (h->root.root.u.def.section)
&& (!ELF_ST_IS_MIPS16 (h->root.other)
|| (h->fn_stub && h->need_fn_stub))
&& (PIC_OBJECT_P (h->root.root.u.def.section->owner)
|| ELF_ST_IS_MIPS_PIC (h->root.other)));
}
/* Set *SEC to the input section that contains the target of STUB.
Return the offset of the target from the start of that section. */
static bfd_vma
mips_elf_get_la25_target (struct mips_elf_la25_stub *stub,
asection **sec)
{
if (ELF_ST_IS_MIPS16 (stub->h->root.other))
{
BFD_ASSERT (stub->h->need_fn_stub);
*sec = stub->h->fn_stub;
return 0;
}
else
{
*sec = stub->h->root.root.u.def.section;
return stub->h->root.root.u.def.value;
}
}
/* 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 bool
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);
if (htab == NULL)
return false;
/* 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. */
mips_elf_get_la25_target (stub, &input_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, 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 bool
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);
if (htab == NULL)
return false;
/* 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, 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 bool
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;
bool use_trampoline_p;
asection *s;
bfd_vma value;
void **slot;
/* 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);
if (htab == NULL)
return false;
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;
/* 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. */
value = mips_elf_get_la25_target (stub, &s);
if (ELF_ST_IS_MICROMIPS (stub->h->root.other))
value &= ~1;
use_trampoline_p = (value != 0 || s->alignment_power > 4);
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 bool
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 (!bfd_link_relocatable (hti->info))
mips_elf_check_mips16_stubs (hti->info, h);
if (mips_elf_local_pic_function_p (h))
{
/* PR 12845: If H is in a section that has been garbage
collected it will have its output section set to *ABS*. */
if (bfd_is_abs_section (h->root.root.u.def.section->output_section))
return true;
/* 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 (bfd_link_relocatable (hti->info))
{
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;
}
/* R_MIPS16_26 is used for the mips16 jal and jalx instructions.
Most mips16 instructions are 16 bits, but these instructions
are 32 bits.
The format of these instructions is:
+--------------+--------------------------------+
| JALX | X| Imm 20:16 | Imm 25:21 |
+--------------+--------------------------------+
| Immediate 15:0 |
+-----------------------------------------------+
JALX is the 5-bit value 00011. X is 0 for jal, 1 for jalx.
Note that the immediate value in the first word is swapped.
When producing a relocatable object file, R_MIPS16_26 is
handled mostly like R_MIPS_26. In particular, the addend is
stored as a straight 26-bit value in a 32-bit instruction.
(gas makes life simpler for itself by never adjusting a
R_MIPS16_26 reloc to be against a section, so the addend is
always zero). However, the 32 bit instruction is stored as 2
16-bit values, rather than a single 32-bit value. In a
big-endian file, the result is the same; in a little-endian
file, the two 16-bit halves of the 32 bit value are swapped.
This is so that a disassembler can recognize the jal
instruction.
When doing a final link, R_MIPS16_26 is treated as a 32 bit
instruction stored as two 16-bit values. The addend A is the
contents of the targ26 field. The calculation is the same as
R_MIPS_26. When storing the calculated value, reorder the
immediate value as shown above, and don't forget to store the
value as two 16-bit values.
To put it in MIPS ABI terms, the relocation field is T-targ26-16,
defined as
big-endian:
+--------+----------------------+
| | |
| | targ26-16 |
|31 26|25 0|
+--------+----------------------+
little-endian:
+----------+------+-------------+
| | | |
| sub1 | | sub2 |
|0 9|10 15|16 31|
+----------+--------------------+
where targ26-16 is sub1 followed by sub2 (i.e., the addend field A is
((sub1 << 16) | sub2)).
When producing a relocatable object file, the calculation is
(((A < 2) | ((P + 4) & 0xf0000000) + S) >> 2)
When producing a fully linked file, the calculation is
let R = (((A < 2) | ((P + 4) & 0xf0000000) + S) >> 2)
((R & 0x1f0000) << 5) | ((R & 0x3e00000) >> 5) | (R & 0xffff)
The table below lists the other MIPS16 instruction relocations.
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 |
+--------------+--------------------------------+
| Major | rx | ry | Imm 4:0 |
+--------------+--------------------------------+
EXTEND is the five bit value 11110. Major is the instruction
opcode.
All we need to do here is shuffle the bits appropriately.
As above, the two 16-bit halves must be swapped on a
little-endian system.
Finally R_MIPS16_PC16_S1 corresponds to R_MIPS_PC16, however the
relocatable field is shifted by 1 rather than 2 and the same bit
shuffling is done as with the relocations above. */
static inline bool
mips16_reloc_p (int r_type)
{
switch (r_type)
{
case R_MIPS16_26:
case R_MIPS16_GPREL:
case R_MIPS16_GOT16:
case R_MIPS16_CALL16:
case R_MIPS16_HI16:
case R_MIPS16_LO16:
case R_MIPS16_TLS_GD:
case R_MIPS16_TLS_LDM:
case R_MIPS16_TLS_DTPREL_HI16:
case R_MIPS16_TLS_DTPREL_LO16:
case R_MIPS16_TLS_GOTTPREL:
case R_MIPS16_TLS_TPREL_HI16:
case R_MIPS16_TLS_TPREL_LO16:
case R_MIPS16_PC16_S1:
return true;
default:
return false;
}
}
/* Check if a microMIPS reloc. */
static inline bool
micromips_reloc_p (unsigned int r_type)
{
return r_type >= R_MICROMIPS_min && r_type < R_MICROMIPS_max;
}
/* Similar to MIPS16, the two 16-bit halves in microMIPS must be swapped
on a little-endian system. This does not apply to R_MICROMIPS_PC7_S1,
R_MICROMIPS_PC10_S1 and R_MICROMIPS_GPREL7_S2 relocs that apply to
16-bit instructions. */
static inline bool
micromips_reloc_shuffle_p (unsigned int r_type)
{
return (micromips_reloc_p (r_type)
&& r_type != R_MICROMIPS_PC7_S1
&& r_type != R_MICROMIPS_PC10_S1
&& r_type != R_MICROMIPS_GPREL7_S2);
}
static inline bool
got16_reloc_p (int r_type)
{
return (r_type == R_MIPS_GOT16
|| r_type == R_MIPS16_GOT16
|| r_type == R_MICROMIPS_GOT16);
}
static inline bool
call16_reloc_p (int r_type)
{
return (r_type == R_MIPS_CALL16
|| r_type == R_MIPS16_CALL16
|| r_type == R_MICROMIPS_CALL16);
}
static inline bool
got_disp_reloc_p (unsigned int r_type)
{
return r_type == R_MIPS_GOT_DISP || r_type == R_MICROMIPS_GOT_DISP;
}
static inline bool
got_page_reloc_p (unsigned int r_type)
{
return r_type == R_MIPS_GOT_PAGE || r_type == R_MICROMIPS_GOT_PAGE;
}
static inline bool
got_lo16_reloc_p (unsigned int r_type)
{
return r_type == R_MIPS_GOT_LO16 || r_type == R_MICROMIPS_GOT_LO16;
}
static inline bool
call_hi16_reloc_p (unsigned int r_type)
{
return r_type == R_MIPS_CALL_HI16 || r_type == R_MICROMIPS_CALL_HI16;
}
static inline bool
call_lo16_reloc_p (unsigned int r_type)
{
return r_type == R_MIPS_CALL_LO16 || r_type == R_MICROMIPS_CALL_LO16;
}
static inline bool
hi16_reloc_p (int r_type)
{
return (r_type == R_MIPS_HI16
|| r_type == R_MIPS16_HI16
|| r_type == R_MICROMIPS_HI16
|| r_type == R_MIPS_PCHI16);
}
static inline bool
lo16_reloc_p (int r_type)
{
return (r_type == R_MIPS_LO16
|| r_type == R_MIPS16_LO16
|| r_type == R_MICROMIPS_LO16
|| r_type == R_MIPS_PCLO16);
}
static inline bool
mips16_call_reloc_p (int r_type)
{
return r_type == R_MIPS16_26 || r_type == R_MIPS16_CALL16;
}
static inline bool
jal_reloc_p (int r_type)
{
return (r_type == R_MIPS_26
|| r_type == R_MIPS16_26
|| r_type == R_MICROMIPS_26_S1);
}
static inline bool
b_reloc_p (int r_type)
{
return (r_type == R_MIPS_PC26_S2
|| r_type == R_MIPS_PC21_S2
|| r_type == R_MIPS_PC16
|| r_type == R_MIPS_GNU_REL16_S2
|| r_type == R_MIPS16_PC16_S1
|| r_type == R_MICROMIPS_PC16_S1
|| r_type == R_MICROMIPS_PC10_S1
|| r_type == R_MICROMIPS_PC7_S1);
}
static inline bool
aligned_pcrel_reloc_p (int r_type)
{
return (r_type == R_MIPS_PC18_S3
|| r_type == R_MIPS_PC19_S2);
}
static inline bool
branch_reloc_p (int r_type)
{
return (r_type == R_MIPS_26
|| r_type == R_MIPS_PC26_S2
|| r_type == R_MIPS_PC21_S2
|| r_type == R_MIPS_PC16
|| r_type == R_MIPS_GNU_REL16_S2);
}
static inline bool
mips16_branch_reloc_p (int r_type)
{
return (r_type == R_MIPS16_26
|| r_type == R_MIPS16_PC16_S1);
}
static inline bool
micromips_branch_reloc_p (int r_type)
{
return (r_type == R_MICROMIPS_26_S1
|| r_type == R_MICROMIPS_PC16_S1
|| r_type == R_MICROMIPS_PC10_S1
|| r_type == R_MICROMIPS_PC7_S1);
}
static inline bool
tls_gd_reloc_p (unsigned int r_type)
{
return (r_type == R_MIPS_TLS_GD
|| r_type == R_MIPS16_TLS_GD
|| r_type == R_MICROMIPS_TLS_GD);
}
static inline bool
tls_ldm_reloc_p (unsigned int r_type)
{
return (r_type == R_MIPS_TLS_LDM
|| r_type == R_MIPS16_TLS_LDM
|| r_type == R_MICROMIPS_TLS_LDM);
}
static inline bool
tls_gottprel_reloc_p (unsigned int r_type)
{
return (r_type == R_MIPS_TLS_GOTTPREL
|| r_type == R_MIPS16_TLS_GOTTPREL
|| r_type == R_MICROMIPS_TLS_GOTTPREL);
}
static inline bool
needs_shuffle (int r_type)
{
return mips16_reloc_p (r_type) || micromips_reloc_shuffle_p (r_type);
}
void
_bfd_mips_elf_reloc_unshuffle (bfd *abfd, int r_type,
bool jal_shuffle, bfd_byte *data)
{
bfd_vma first, second, val;
if (!needs_shuffle (r_type))
return;
/* Pick up the first and second halfwords of the instruction. */
first = bfd_get_16 (abfd, data);
second = bfd_get_16 (abfd, data + 2);
if (micromips_reloc_p (r_type) || (r_type == R_MIPS16_26 && !jal_shuffle))
val = first << 16 | second;
else if (r_type != R_MIPS16_26)
val = (((first & 0xf800) << 16) | ((second & 0xffe0) << 11)
| ((first & 0x1f) << 11) | (first & 0x7e0) | (second & 0x1f));
else
val = (((first & 0xfc00) << 16) | ((first & 0x3e0) << 11)
| ((first & 0x1f) << 21) | second);
bfd_put_32 (abfd, val, data);
}
void
_bfd_mips_elf_reloc_shuffle (bfd *abfd, int r_type,
bool jal_shuffle, bfd_byte *data)
{
bfd_vma first, second, val;
if (!needs_shuffle (r_type))
return;
val = bfd_get_32 (abfd, data);
if (micromips_reloc_p (r_type) || (r_type == R_MIPS16_26 && !jal_shuffle))
{
second = val & 0xffff;
first = val >> 16;
}
else if (r_type != R_MIPS16_26)
{
second = ((val >> 11) & 0xffe0) | (val & 0x1f);
first = ((val >> 16) & 0xf800) | ((val >> 11) & 0x1f) | (val & 0x7e0);
}
else
{
second = val & 0xffff;
first = ((val >> 16) & 0xfc00) | ((val >> 11) & 0x3e0)
| ((val >> 21) & 0x1f);
}
bfd_put_16 (abfd, second, data + 2);
bfd_put_16 (abfd, first, data);
}
/* Perform reloc offset checking.
We can only use bfd_reloc_offset_in_range, which takes into account
the size of the field being relocated, when section contents will
be accessed because mips object files may use relocations that seem
to access beyond section limits.
gas/testsuite/gas/mips/dla-reloc.s is an example that puts
R_MIPS_SUB, a 64-bit relocation, on the last instruction in the
section. The R_MIPS_SUB applies to the addend for the next reloc
rather than the section contents.
CHECK is CHECK_STD for the standard bfd_reloc_offset_in_range check,
CHECK_INPLACE to only check partial_inplace relocs, and
CHECK_SHUFFLE to only check relocs that shuffle/unshuffle. */
bool
_bfd_mips_reloc_offset_in_range (bfd *abfd, asection *input_section,
arelent *reloc_entry, enum reloc_check check)
{
if (check == check_inplace && !reloc_entry->howto->partial_inplace)
return true;
if (check == check_shuffle && !needs_shuffle (reloc_entry->howto->type))
return true;
return bfd_reloc_offset_in_range (reloc_entry->howto, abfd,
input_section, reloc_entry->address);
}
bfd_reloc_status_type
_bfd_mips_elf_gprel16_with_gp (bfd *abfd, asymbol *symbol,
arelent *reloc_entry, asection *input_section,
bool relocatable, void *data, bfd_vma gp)
{
bfd_vma relocation;
bfd_signed_vma val;
bfd_reloc_status_type status;
if (bfd_is_com_section (symbol->section))
relocation = 0;
else
relocation = symbol->value;
if (symbol->section->output_section != NULL)
{
relocation += symbol->section->output_section->vma;
relocation += symbol->section->output_offset;
}
/* Set val to the offset into the section or symbol. */
val = reloc_entry->addend;
_bfd_mips_elf_sign_extend (val, 16);
/* Adjust val for the final section location and GP value. If we
are producing relocatable output, we don't want to do this for
an external symbol. */
if (! relocatable
|| (symbol->flags & BSF_SECTION_SYM) != 0)
val += relocation - gp;
if (reloc_entry->howto->partial_inplace)
{
if (!bfd_reloc_offset_in_range (reloc_entry->howto, abfd, input_section,
reloc_entry->address))
return bfd_reloc_outofrange;
status = _bfd_relocate_contents (reloc_entry->howto, abfd, val,
(bfd_byte *) data
+ reloc_entry->address);
if (status != bfd_reloc_ok)
return status;
}
else
reloc_entry->addend = val;
if (relocatable)
reloc_entry->address += input_section->output_offset;
return bfd_reloc_ok;
}
/* A howto special_function for REL *HI16 relocations. We can only
calculate the correct value once we've seen the partnering
*LO16 relocation, so just save the information for later.
The ABI requires that the *LO16 immediately follow the *HI16.
However, as a GNU extension, we permit an arbitrary number of
*HI16s to be associated with a single *LO16. This significantly
simplies the relocation handling in gcc. */
bfd_reloc_status_type
_bfd_mips_elf_hi16_reloc (bfd *abfd, arelent *reloc_entry,
asymbol *symbol ATTRIBUTE_UNUSED, void *data,
asection *input_section, bfd *output_bfd,
char **error_message ATTRIBUTE_UNUSED)
{
struct mips_hi16 *n;
struct mips_elf_obj_tdata *tdata;
if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
return bfd_reloc_outofrange;
n = bfd_malloc (sizeof *n);
if (n == NULL)
return bfd_reloc_outofrange;
tdata = mips_elf_tdata (abfd);
n->next = tdata->mips_hi16_list;
n->data = data;
n->input_section = input_section;
n->rel = *reloc_entry;
tdata->mips_hi16_list = n;
if (output_bfd != NULL)
reloc_entry->address += input_section->output_offset;
return bfd_reloc_ok;
}
/* 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
treated in the same as R_MIPS_HI16 when applied to local symbols. */
bfd_reloc_status_type
_bfd_mips_elf_got16_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
void *data, asection *input_section,
bfd *output_bfd, char **error_message)
{
if ((symbol->flags & (BSF_GLOBAL | BSF_WEAK)) != 0
|| bfd_is_und_section (bfd_asymbol_section (symbol))
|| bfd_is_com_section (bfd_asymbol_section (symbol)))
/* The relocation is against a global symbol. */
return _bfd_mips_elf_generic_reloc (abfd, reloc_entry, symbol, data,
input_section, output_bfd,
error_message);
return _bfd_mips_elf_hi16_reloc (abfd, reloc_entry, symbol, data,
input_section, output_bfd, error_message);
}
/* A howto special_function for REL *LO16 relocations. The *LO16 itself
is a straightforward 16 bit inplace relocation, but we must deal with
any partnering high-part relocations as well. */
bfd_reloc_status_type
_bfd_mips_elf_lo16_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
void *data, asection *input_section,
bfd *output_bfd, char **error_message)
{
bfd_vma vallo;
bfd_byte *location = (bfd_byte *) data + reloc_entry->address;
struct mips_elf_obj_tdata *tdata;
if (!bfd_reloc_offset_in_range (reloc_entry->howto, abfd, input_section,
reloc_entry->address))
return bfd_reloc_outofrange;
_bfd_mips_elf_reloc_unshuffle (abfd, reloc_entry->howto->type, false,
location);
/* The high 16 bits of the addend are stored in the high insn, the
low 16 bits in the low insn, but there is a catch: You can't
just concatenate the high and low parts. The high part of the
addend is adjusted for the fact that the low part is sign
extended. For example, an addend of 0x38000 would have 0x0004 in
the high part and 0x8000 (=0xff..f8000) in the low part.
To extract the actual addend, calculate (a)
((hi & 0xffff) << 16) + ((lo & 0xffff) ^ 0x8000) - 0x8000.
We will be applying (symbol + addend) & 0xffff to the low insn,
and we want to apply (b) (symbol + addend + 0x8000) >> 16 to the
high insn (the +0x8000 adjusting for when the applied low part is
negative). Substituting (a) into (b) and recognising that
(hi & 0xffff) is already in the high insn gives a high part
addend adjustment of (lo & 0xffff) ^ 0x8000. */
vallo = (bfd_get_32 (abfd, location) & 0xffff) ^ 0x8000;
_bfd_mips_elf_reloc_shuffle (abfd, reloc_entry->howto->type, false,
location);
tdata = mips_elf_tdata (abfd);
while (tdata->mips_hi16_list != NULL)
{
bfd_reloc_status_type ret;
struct mips_hi16 *hi;
hi = tdata->mips_hi16_list;
/* 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
relocation (with a rightshift of 16). However, since GOT16
relocations can also be used with global symbols, their howto
has a rightshift of 0. */
if (hi->rel.howto->type == R_MIPS_GOT16)
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);
else if (hi->rel.howto->type == R_MICROMIPS_GOT16)
hi->rel.howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, R_MICROMIPS_HI16, false);
hi->rel.addend += vallo;
ret = _bfd_mips_elf_generic_reloc (abfd, &hi->rel, symbol, hi->data,
hi->input_section, output_bfd,
error_message);
if (ret != bfd_reloc_ok)
return ret;
tdata->mips_hi16_list = hi->next;
free (hi);
}
return _bfd_mips_elf_generic_reloc (abfd, reloc_entry, symbol, data,
input_section, output_bfd,
error_message);
}
/* A generic howto special_function. This calculates and installs the
relocation itself, thus avoiding the oft-discussed problems in
bfd_perform_relocation and bfd_install_relocation. */
bfd_reloc_status_type
_bfd_mips_elf_generic_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry,
asymbol *symbol, void *data ATTRIBUTE_UNUSED,
asection *input_section, bfd *output_bfd,
char **error_message ATTRIBUTE_UNUSED)
{
bfd_signed_vma val;
bfd_reloc_status_type status;
bool relocatable;
relocatable = (output_bfd != NULL);
if (!_bfd_mips_reloc_offset_in_range (abfd, input_section, reloc_entry,
(relocatable
? check_inplace : check_std)))
return bfd_reloc_outofrange;
/* Build up the field adjustment in VAL. */
val = 0;
if ((!relocatable || (symbol->flags & BSF_SECTION_SYM) != 0)
&& symbol->section->output_section != NULL)
{
/* Either we're calculating the final field value or we have a
relocation against a section symbol. Add in the section's
offset or address. */
val += symbol->section->output_section->vma;
val += symbol->section->output_offset;
}
if (!relocatable)
{
/* We're calculating the final field value. Add in the symbol's value
and, if pc-relative, subtract the address of the field itself. */
val += symbol->value;
if (reloc_entry->howto->pc_relative)
{
val -= input_section->output_section->vma;
val -= input_section->output_offset;
val -= reloc_entry->address;
}
}
/* VAL is now the final adjustment. If we're keeping this relocation
in the output file, and if the relocation uses a separate addend,
we just need to add VAL to that addend. Otherwise we need to add
VAL to the relocation field itself. */
if (relocatable && !reloc_entry->howto->partial_inplace)
reloc_entry->addend += val;
else
{
bfd_byte *location = (bfd_byte *) data + reloc_entry->address;
/* Add in the separate addend, if any. */
val += reloc_entry->addend;
/* Add VAL to the relocation field. */
_bfd_mips_elf_reloc_unshuffle (abfd, reloc_entry->howto->type, false,
location);
status = _bfd_relocate_contents (reloc_entry->howto, abfd, val,
location);
_bfd_mips_elf_reloc_shuffle (abfd, reloc_entry->howto->type, false,
location);
if (status != bfd_reloc_ok)
return status;
}
if (relocatable)
reloc_entry->address += input_section->output_offset;
return bfd_reloc_ok;
}
/* Swap an entry in a .gptab section. Note that these routines rely
on the equivalence of the two elements of the union. */
static void
bfd_mips_elf32_swap_gptab_in (bfd *abfd, const Elf32_External_gptab *ex,
Elf32_gptab *in)
{
in->gt_entry.gt_g_value = H_GET_32 (abfd, ex->gt_entry.gt_g_value);
in->gt_entry.gt_bytes = H_GET_32 (abfd, ex->gt_entry.gt_bytes);
}
static void
bfd_mips_elf32_swap_gptab_out (bfd *abfd, const Elf32_gptab *in,
Elf32_External_gptab *ex)
{
H_PUT_32 (abfd, in->gt_entry.gt_g_value, ex->gt_entry.gt_g_value);
H_PUT_32 (abfd, in->gt_entry.gt_bytes, ex->gt_entry.gt_bytes);
}
static void
bfd_elf32_swap_compact_rel_out (bfd *abfd, const Elf32_compact_rel *in,
Elf32_External_compact_rel *ex)
{
H_PUT_32 (abfd, in->id1, ex->id1);
H_PUT_32 (abfd, in->num, ex->num);
H_PUT_32 (abfd, in->id2, ex->id2);
H_PUT_32 (abfd, in->offset, ex->offset);
H_PUT_32 (abfd, in->reserved0, ex->reserved0);
H_PUT_32 (abfd, in->reserved1, ex->reserved1);
}
static void
bfd_elf32_swap_crinfo_out (bfd *abfd, const Elf32_crinfo *in,
Elf32_External_crinfo *ex)
{
unsigned long l;
l = (((in->ctype & CRINFO_CTYPE) << CRINFO_CTYPE_SH)
| ((in->rtype & CRINFO_RTYPE) << CRINFO_RTYPE_SH)
| ((in->dist2to & CRINFO_DIST2TO) << CRINFO_DIST2TO_SH)
| ((in->relvaddr & CRINFO_RELVADDR) << CRINFO_RELVADDR_SH));
H_PUT_32 (abfd, l, ex->info);
H_PUT_32 (abfd, in->konst, ex->konst);
H_PUT_32 (abfd, in->vaddr, ex->vaddr);
}
/* A .reginfo section holds a single Elf32_RegInfo structure. These
routines swap this structure in and out. They are used outside of
BFD, so they are globally visible. */
void
bfd_mips_elf32_swap_reginfo_in (bfd *abfd, const Elf32_External_RegInfo *ex,
Elf32_RegInfo *in)
{
in->ri_gprmask = H_GET_32 (abfd, ex->ri_gprmask);
in->ri_cprmask[0] = H_GET_32 (abfd, ex->ri_cprmask[0]);
in->ri_cprmask[1] = H_GET_32 (abfd, ex->ri_cprmask[1]);
in->ri_cprmask[2] = H_GET_32 (abfd, ex->ri_cprmask[2]);
in->ri_cprmask[3] = H_GET_32 (abfd, ex->ri_cprmask[3]);
in->ri_gp_value = H_GET_32 (abfd, ex->ri_gp_value);
}
void
bfd_mips_elf32_swap_reginfo_out (bfd *abfd, const Elf32_RegInfo *in,
Elf32_External_RegInfo *ex)
{
H_PUT_32 (abfd, in->ri_gprmask, ex->ri_gprmask);
H_PUT_32 (abfd, in->ri_cprmask[0], ex->ri_cprmask[0]);
H_PUT_32 (abfd, in->ri_cprmask[1], ex->ri_cprmask[1]);
H_PUT_32 (abfd, in->ri_cprmask[2], ex->ri_cprmask[2]);
H_PUT_32 (abfd, in->ri_cprmask[3], ex->ri_cprmask[3]);
H_PUT_32 (abfd, in->ri_gp_value, ex->ri_gp_value);
}
/* In the 64 bit ABI, the .MIPS.options section holds register
information in an Elf64_Reginfo structure. These routines swap
them in and out. They are globally visible because they are used
outside of BFD. These routines are here so that gas can call them
without worrying about whether the 64 bit ABI has been included. */
void
bfd_mips_elf64_swap_reginfo_in (bfd *abfd, const Elf64_External_RegInfo *ex,
Elf64_Internal_RegInfo *in)
{
in->ri_gprmask = H_GET_32 (abfd, ex->ri_gprmask);
in->ri_pad = H_GET_32 (abfd, ex->ri_pad);
in->ri_cprmask[0] = H_GET_32 (abfd, ex->ri_cprmask[0]);
in->ri_cprmask[1] = H_GET_32 (abfd, ex->ri_cprmask[1]);
in->ri_cprmask[2] = H_GET_32 (abfd, ex->ri_cprmask[2]);
in->ri_cprmask[3] = H_GET_32 (abfd, ex->ri_cprmask[3]);
in->ri_gp_value = H_GET_64 (abfd, ex->ri_gp_value);
}
void
bfd_mips_elf64_swap_reginfo_out (bfd *abfd, const Elf64_Internal_RegInfo *in,
Elf64_External_RegInfo *ex)
{
H_PUT_32 (abfd, in->ri_gprmask, ex->ri_gprmask);
H_PUT_32 (abfd, in->ri_pad, ex->ri_pad);
H_PUT_32 (abfd, in->ri_cprmask[0], ex->ri_cprmask[0]);
H_PUT_32 (abfd, in->ri_cprmask[1], ex->ri_cprmask[1]);
H_PUT_32 (abfd, in->ri_cprmask[2], ex->ri_cprmask[2]);
H_PUT_32 (abfd, in->ri_cprmask[3], ex->ri_cprmask[3]);
H_PUT_64 (abfd, in->ri_gp_value, ex->ri_gp_value);
}
/* Swap in an options header. */
void
bfd_mips_elf_swap_options_in (bfd *abfd, const Elf_External_Options *ex,
Elf_Internal_Options *in)
{
in->kind = H_GET_8 (abfd, ex->kind);
in->size = H_GET_8 (abfd, ex->size);
in->section = H_GET_16 (abfd, ex->section);
in->info = H_GET_32 (abfd, ex->info);
}
/* Swap out an options header. */
void
bfd_mips_elf_swap_options_out (bfd *abfd, const Elf_Internal_Options *in,
Elf_External_Options *ex)
{
H_PUT_8 (abfd, in->kind, ex->kind);
H_PUT_8 (abfd, in->size, ex->size);
H_PUT_16 (abfd, in->section, ex->section);
H_PUT_32 (abfd, in->info, ex->info);
}
/* Swap in an abiflags structure. */
void
bfd_mips_elf_swap_abiflags_v0_in (bfd *abfd,
const Elf_External_ABIFlags_v0 *ex,
Elf_Internal_ABIFlags_v0 *in)
{
in->version = H_GET_16 (abfd, ex->version);
in->isa_level = H_GET_8 (abfd, ex->isa_level);
in->isa_rev = H_GET_8 (abfd, ex->isa_rev);
in->gpr_size = H_GET_8 (abfd, ex->gpr_size);
in->cpr1_size = H_GET_8 (abfd, ex->cpr1_size);
in->cpr2_size = H_GET_8 (abfd, ex->cpr2_size);
in->fp_abi = H_GET_8 (abfd, ex->fp_abi);
in->isa_ext = H_GET_32 (abfd, ex->isa_ext);
in->ases = H_GET_32 (abfd, ex->ases);
in->flags1 = H_GET_32 (abfd, ex->flags1);
in->flags2 = H_GET_32 (abfd, ex->flags2);
}
/* Swap out an abiflags structure. */
void
bfd_mips_elf_swap_abiflags_v0_out (bfd *abfd,
const Elf_Internal_ABIFlags_v0 *in,
Elf_External_ABIFlags_v0 *ex)
{
H_PUT_16 (abfd, in->version, ex->version);
H_PUT_8 (abfd, in->isa_level, ex->isa_level);
H_PUT_8 (abfd, in->isa_rev, ex->isa_rev);
H_PUT_8 (abfd, in->gpr_size, ex->gpr_size);
H_PUT_8 (abfd, in->cpr1_size, ex->cpr1_size);
H_PUT_8 (abfd, in->cpr2_size, ex->cpr2_size);
H_PUT_8 (abfd, in->fp_abi, ex->fp_abi);
H_PUT_32 (abfd, in->isa_ext, ex->isa_ext);
H_PUT_32 (abfd, in->ases, ex->ases);
H_PUT_32 (abfd, in->flags1, ex->flags1);
H_PUT_32 (abfd, in->flags2, ex->flags2);
}
/* This function is called via qsort() to sort the dynamic relocation
entries by increasing r_symndx value. */
static int
sort_dynamic_relocs (const void *arg1, const void *arg2)
{
Elf_Internal_Rela int_reloc1;
Elf_Internal_Rela int_reloc2;
int diff;
bfd_elf32_swap_reloc_in (reldyn_sorting_bfd, arg1, &int_reloc1);
bfd_elf32_swap_reloc_in (reldyn_sorting_bfd, arg2, &int_reloc2);
diff = ELF32_R_SYM (int_reloc1.r_info) - ELF32_R_SYM (int_reloc2.r_info);
if (diff != 0)
return diff;
if (int_reloc1.r_offset < int_reloc2.r_offset)
return -1;
if (int_reloc1.r_offset > int_reloc2.r_offset)
return 1;
return 0;
}
/* Like sort_dynamic_relocs, but used for elf64 relocations. */
static int
sort_dynamic_relocs_64 (const void *arg1 ATTRIBUTE_UNUSED,
const void *arg2 ATTRIBUTE_UNUSED)
{
#ifdef BFD64
Elf_Internal_Rela int_reloc1[3];
Elf_Internal_Rela int_reloc2[3];
(*get_elf_backend_data (reldyn_sorting_bfd)->s->swap_reloc_in)
(reldyn_sorting_bfd, arg1, int_reloc1);
(*get_elf_backend_data (reldyn_sorting_bfd)->s->swap_reloc_in)
(reldyn_sorting_bfd, arg2, int_reloc2);
if (ELF64_R_SYM (int_reloc1[0].r_info) < ELF64_R_SYM (int_reloc2[0].r_info))
return -1;
if (ELF64_R_SYM (int_reloc1[0].r_info) > ELF64_R_SYM (int_reloc2[0].r_info))
return 1;
if (int_reloc1[0].r_offset < int_reloc2[0].r_offset)
return -1;
if (int_reloc1[0].r_offset > int_reloc2[0].r_offset)
return 1;
return 0;
#else
abort ();
#endif
}
/* This routine is used to write out ECOFF debugging external symbol
information. It is called via mips_elf_link_hash_traverse. The
ECOFF external symbol information must match the ELF external
symbol information. Unfortunately, at this point we don't know
whether a symbol is required by reloc information, so the two
tables may wind up being different. We must sort out the external
symbol information before we can set the final size of the .mdebug
section, and we must set the size of the .mdebug section before we
can relocate any sections, and we can't know which symbols are
required by relocation until we relocate the sections.
Fortunately, it is relatively unlikely that any symbol will be
stripped but required by a reloc. In particular, it can not happen
when generating a final executable. */
static bool
mips_elf_output_extsym (struct mips_elf_link_hash_entry *h, void *data)
{
struct extsym_info *einfo = data;
bool strip;
asection *sec, *output_section;
if (h->root.indx == -2)
strip = false;
else if ((h->root.def_dynamic
|| h->root.ref_dynamic
|| h->root.type == bfd_link_hash_new)
&& !h->root.def_regular
&& !h->root.ref_regular)
strip = true;
else if (einfo->info->strip == strip_all
|| (einfo->info->strip == strip_some
&& bfd_hash_lookup (einfo->info->keep_hash,
h->root.root.root.string,
false, false) == NULL))
strip = true;
else
strip = false;
if (strip)
return true;
if (h->esym.ifd == -2)
{
h->esym.jmptbl = 0;
h->esym.cobol_main = 0;
h->esym.weakext = 0;
h->esym.reserved = 0;
h->esym.ifd = ifdNil;
h->esym.asym.value = 0;
h->esym.asym.st = stGlobal;
if (h->root.root.type == bfd_link_hash_undefined
|| h->root.root.type == bfd_link_hash_undefweak)
{
const char *name;
/* Use undefined class. Also, set class and type for some
special symbols. */
name = h->root.root.root.string;
if (strcmp (name, mips_elf_dynsym_rtproc_names[0]) == 0
|| strcmp (name, mips_elf_dynsym_rtproc_names[1]) == 0)
{
h->esym.asym.sc = scData;
h->esym.asym.st = stLabel;
h->esym.asym.value = 0;
}
else if (strcmp (name, mips_elf_dynsym_rtproc_names[2]) == 0)
{
h->esym.asym.sc = scAbs;
h->esym.asym.st = stLabel;
h->esym.asym.value =
mips_elf_hash_table (einfo->info)->procedure_count;
}
else
h->esym.asym.sc = scUndefined;
}
else if (h->root.root.type != bfd_link_hash_defined
&& h->root.root.type != bfd_link_hash_defweak)
h->esym.asym.sc = scAbs;
else
{
const char *name;
sec = h->root.root.u.def.section;
output_section = sec->output_section;
/* When making a shared library and symbol h is the one from
the another shared library, OUTPUT_SECTION may be null. */
if (output_section == NULL)
h->esym.asym.sc = scUndefined;
else
{
name = bfd_section_name (output_section);
if (strcmp (name, ".text") == 0)
h->esym.asym.sc = scText;
else if (strcmp (name, ".data") == 0)
h->esym.asym.sc = scData;
else if (strcmp (name, ".sdata") == 0)
h->esym.asym.sc = scSData;
else if (strcmp (name, ".rodata") == 0
|| strcmp (name, ".rdata") == 0)
h->esym.asym.sc = scRData;
else if (strcmp (name, ".bss") == 0)
h->esym.asym.sc = scBss;
else if (strcmp (name, ".sbss") == 0)
h->esym.asym.sc = scSBss;
else if (strcmp (name, ".init") == 0)
h->esym.asym.sc = scInit;
else if (strcmp (name, ".fini") == 0)
h->esym.asym.sc = scFini;
else
h->esym.asym.sc = scAbs;
}
}
h->esym.asym.reserved = 0;
h->esym.asym.index = indexNil;
}
if (h->root.root.type == bfd_link_hash_common)
h->esym.asym.value = h->root.root.u.c.size;
else if (h->root.root.type == bfd_link_hash_defined
|| h->root.root.type == bfd_link_hash_defweak)
{
if (h->esym.asym.sc == scCommon)
h->esym.asym.sc = scBss;
else if (h->esym.asym.sc == scSCommon)
h->esym.asym.sc = scSBss;
sec = h->root.root.u.def.section;
output_section = sec->output_section;
if (output_section != NULL)
h->esym.asym.value = (h->root.root.u.def.value
+ sec->output_offset
+ output_section->vma);
else
h->esym.asym.value = 0;
}
else
{
struct mips_elf_link_hash_entry *hd = h;
while (hd->root.root.type == bfd_link_hash_indirect)
hd = (struct mips_elf_link_hash_entry *)h->root.root.u.i.link;
if (hd->needs_lazy_stub)
{
BFD_ASSERT (hd->root.plt.plist != NULL);
BFD_ASSERT (hd->root.plt.plist->stub_offset != MINUS_ONE);
/* Set type and value for a symbol with a function stub. */
h->esym.asym.st = stProc;
sec = hd->root.root.u.def.section;
if (sec == NULL)
h->esym.asym.value = 0;
else
{
output_section = sec->output_section;
if (output_section != NULL)
h->esym.asym.value = (hd->root.plt.plist->stub_offset
+ sec->output_offset
+ output_section->vma);
else
h->esym.asym.value = 0;
}
}
}
if (! bfd_ecoff_debug_one_external (einfo->abfd, einfo->debug, einfo->swap,
h->root.root.root.string,
&h->esym))
{