/* MIPS-specific support for ELF
Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
- 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+ 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
+ Free Software Foundation, Inc.
Most of the information added by Ian Lance Taylor, Cygnus Support,
<ian@cygnus.com>.
(abfd == NULL)
(2) SYMBOL + OFFSET addresses, where SYMBOL is local to an input bfd
(abfd != NULL, symndx >= 0)
- (3) global and forced-local symbols
+ (3) SYMBOL addresses, where SYMBOL is not local to an input bfd
(abfd != NULL, symndx == -1)
Type (3) entries are treated differently for different types of GOT.
that should be added to the symbol value. */
bfd_vma addend;
/* If abfd != NULL && symndx == -1, the hash table entry
- corresponding to a global symbol in the got (or, local, if
- h->forced_local). */
+ corresponding to 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;
#define is_mips_elf(bfd) \
(bfd_get_flavour (bfd) == bfd_target_elf_flavour \
&& elf_tdata (bfd) != NULL \
- && elf_object_id (bfd) == MIPS_ELF_TDATA)
+ && 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
#define LA25_LUI(VAL) (0x3c190000 | (VAL)) /* lui t9,VAL */
#define LA25_J(VAL) (0x08000000 | (((VAL) >> 2) & 0x3ffffff)) /* j VAL */
#define LA25_ADDIU(VAL) (0x27390000 | (VAL)) /* addiu t9,t9,VAL */
+#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. */
/* 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;
entry is set to the address of __rld_obj_head as in IRIX5. */
bfd_boolean use_rld_obj_head;
- /* This is the value of the __rld_map or __rld_obj_head symbol. */
- bfd_vma rld_value;
+ /* 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. */
bfd_boolean mips16_stubs_seen;
asection *(*add_stub_section) (const char *, asection *, asection *);
};
+/* Get the MIPS ELF linker hash table from a link_info structure. */
+
+#define mips_elf_hash_table(p) \
+ (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \
+ == 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 {
+struct mips_htab_traverse_info
+{
/* The usual link-wide information. */
struct bfd_link_info *info;
bfd *output_bfd;
|| 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_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. */
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)
#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)
#define MIPS_ELF_RTYPE_TO_HOWTO(abfd, rtype, rela) \
(get_elf_backend_data (abfd)->elf_backend_mips_rtype_to_howto (rtype, rela))
-/* Determine whether the internal relocation of index REL_IDX is REL
- (zero) or RELA (non-zero). The assumption is that, if there are
- two relocation sections for this section, one of them is REL and
- the other is RELA. If the index of the relocation we're testing is
- in range for the first relocation section, check that the external
- relocation size is that for RELA. It is also assumed that, if
- rel_idx is not in range for the first section, and this first
- section contains REL relocs, then the relocation is in the second
- section, that is RELA. */
-#define MIPS_RELOC_RELA_P(abfd, sec, rel_idx) \
- ((NUM_SHDR_ENTRIES (&elf_section_data (sec)->rel_hdr) \
- * get_elf_backend_data (abfd)->s->int_rels_per_ext_rel \
- > (bfd_vma)(rel_idx)) \
- == (elf_section_data (sec)->rel_hdr.sh_entsize \
- == (ABI_64_P (abfd) ? sizeof (Elf64_External_Rela) \
- : sizeof (Elf32_External_Rela))))
-
/* The name of the dynamic relocation section. */
#define MIPS_ELF_REL_DYN_NAME(INFO) \
(mips_elf_hash_table (INFO)->is_vxworks ? ".rela.dyn" : ".rel.dyn")
0x8f990000, /* lw $25, %lo(&GOTPLT[0])($28) */
0x279c0000, /* addiu $28, $28, %lo(&GOTPLT[0]) */
0x031cc023, /* subu $24, $24, $28 */
- 0x03e07821, /* move $15, $31 */
+ 0x03e07821, /* move $15, $31 # 32-bit move (addu) */
0x0018c082, /* srl $24, $24, 2 */
0x0320f809, /* jalr $25 */
0x2718fffe /* subu $24, $24, 2 */
0x8dd90000, /* lw $25, %lo(&GOTPLT[0])($14) */
0x25ce0000, /* addiu $14, $14, %lo(&GOTPLT[0]) */
0x030ec023, /* subu $24, $24, $14 */
- 0x03e07821, /* move $15, $31 */
+ 0x03e07821, /* move $15, $31 # 32-bit move (addu) */
0x0018c082, /* srl $24, $24, 2 */
0x0320f809, /* jalr $25 */
0x2718fffe /* subu $24, $24, 2 */
0xddd90000, /* ld $25, %lo(&GOTPLT[0])($14) */
0x25ce0000, /* addiu $14, $14, %lo(&GOTPLT[0]) */
0x030ec023, /* subu $24, $24, $14 */
- 0x03e07821, /* move $15, $31 */
+ 0x03e0782d, /* move $15, $31 # 64-bit move (daddu) */
0x0018c0c2, /* srl $24, $24, 3 */
0x0320f809, /* jalr $25 */
0x2718fffe /* subu $24, $24, 2 */
0x24180000 /* li t8, <pltindex> */
};
\f
+/* 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);
+}
+\f
/* Look up an entry in a MIPS ELF linker hash table. */
#define mips_elf_link_hash_lookup(table, string, create, copy, follow) \
(bfd_boolean (*) (struct elf_link_hash_entry *, void *)) (func), \
(info)))
-/* Get the MIPS ELF linker hash table from a link_info structure. */
-
-#define mips_elf_hash_table(p) \
- ((struct mips_elf_link_hash_table *) ((p)->hash))
-
/* Find the base offsets for thread-local storage in this object,
for GD/LD and IE/LE respectively. */
ret->call_fp_stub = NULL;
ret->tls_type = GOT_NORMAL;
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;
struct elf_link_hash_entry *elfh;
const char *name;
+ if (ELF_ST_IS_MICROMIPS (h->root.other))
+ value |= 1;
+
/* Create a new symbol. */
name = ACONCAT ((prefix, h->root.root.root.string, NULL));
bh = NULL;
function, or 0 if we can't decide which function that is. */
static unsigned long
-mips16_stub_symndx (asection *sec ATTRIBUTE_UNUSED,
+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. */
- for (rel = relocs; rel < relend; 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);
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);
}
/* Return true if H is a locally-defined PIC function, in the sense
- that it might need $25 to be valid on entry. Note that MIPS16
- functions never need $25 to be valid on entry; they set up $gp
- using PC-relative instructions instead. */
+ 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 bfd_boolean
mips_elf_local_pic_function_p (struct mips_elf_link_hash_entry *h)
|| h->root.root.type == bfd_link_hash_defweak)
&& h->root.def_regular
&& !bfd_is_abs_section (h->root.root.u.def.section)
- && !ELF_ST_IS_MIPS16 (h->root.other)
+ && (!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. */
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."));
sprintf (name, ".text.stub.%d", (int) htab_elements (htab->la25_stubs));
/* Create the section. */
- input_section = stub->h->root.root.u.def.section;
+ mips_elf_get_la25_target (stub, &input_section);
s = htab->add_stub_section (name, input_section,
input_section->output_section);
if (s == NULL)
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;
bfd_vma value;
void **slot;
- /* Prefer to use LUI/ADDIU stubs if the function is at the beginning
- of the section and if we would need no more than 2 nops. */
- s = h->root.root.u.def.section;
- value = h->root.root.u.def.value;
- use_trampoline_p = (value != 0 || s->alignment_power > 4);
-
/* Describe the stub we want. */
search.stub_section = NULL;
search.offset = 0;
/* 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 = 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);
+ use_trampoline_p = (value != 0 || s->alignment_power > 4);
+
h->la25_stub = stub;
return (use_trampoline_p
? mips_elf_add_la25_trampoline (stub, info)
struct mips_htab_traverse_info *hti;
hti = (struct mips_htab_traverse_info *) data;
- if (h->root.root.type == bfd_link_hash_warning)
- h = (struct mips_elf_link_hash_entry *) h->root.root.u.i.link;
-
if (!hti->info->relocatable)
mips_elf_check_mips16_stubs (hti->info, h);
if (mips_elf_local_pic_function_p (h))
{
+ /* 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
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:
return TRUE;
default:
}
}
+/* Check if a microMIPS reloc. */
+
+static inline bfd_boolean
+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
+ and R_MICROMIPS_PC10_S1 relocs that apply to 16-bit instructions. */
+
+static inline bfd_boolean
+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);
+}
+
static inline bfd_boolean
got16_reloc_p (int r_type)
{
- return r_type == R_MIPS_GOT16 || r_type == R_MIPS16_GOT16;
+ return (r_type == R_MIPS_GOT16
+ || r_type == R_MIPS16_GOT16
+ || r_type == R_MICROMIPS_GOT16);
}
static inline bfd_boolean
call16_reloc_p (int r_type)
{
- return r_type == R_MIPS_CALL16 || r_type == R_MIPS16_CALL16;
+ return (r_type == R_MIPS_CALL16
+ || r_type == R_MIPS16_CALL16
+ || r_type == R_MICROMIPS_CALL16);
+}
+
+static inline bfd_boolean
+got_disp_reloc_p (unsigned int r_type)
+{
+ return r_type == R_MIPS_GOT_DISP || r_type == R_MICROMIPS_GOT_DISP;
+}
+
+static inline bfd_boolean
+got_page_reloc_p (unsigned int r_type)
+{
+ return r_type == R_MIPS_GOT_PAGE || r_type == R_MICROMIPS_GOT_PAGE;
+}
+
+static inline bfd_boolean
+got_ofst_reloc_p (unsigned int r_type)
+{
+ return r_type == R_MIPS_GOT_OFST || r_type == R_MICROMIPS_GOT_OFST;
+}
+
+static inline bfd_boolean
+got_hi16_reloc_p (unsigned int r_type)
+{
+ return r_type == R_MIPS_GOT_HI16 || r_type == R_MICROMIPS_GOT_HI16;
+}
+
+static inline bfd_boolean
+got_lo16_reloc_p (unsigned int r_type)
+{
+ return r_type == R_MIPS_GOT_LO16 || r_type == R_MICROMIPS_GOT_LO16;
+}
+
+static inline bfd_boolean
+call_hi16_reloc_p (unsigned int r_type)
+{
+ return r_type == R_MIPS_CALL_HI16 || r_type == R_MICROMIPS_CALL_HI16;
+}
+
+static inline bfd_boolean
+call_lo16_reloc_p (unsigned int r_type)
+{
+ return r_type == R_MIPS_CALL_LO16 || r_type == R_MICROMIPS_CALL_LO16;
}
static inline bfd_boolean
hi16_reloc_p (int r_type)
{
- return r_type == R_MIPS_HI16 || r_type == R_MIPS16_HI16;
+ return (r_type == R_MIPS_HI16
+ || r_type == R_MIPS16_HI16
+ || r_type == R_MICROMIPS_HI16);
}
static inline bfd_boolean
lo16_reloc_p (int r_type)
{
- return r_type == R_MIPS_LO16 || r_type == R_MIPS16_LO16;
+ return (r_type == R_MIPS_LO16
+ || r_type == R_MIPS16_LO16
+ || r_type == R_MICROMIPS_LO16);
}
static inline bfd_boolean
return r_type == R_MIPS16_26 || r_type == R_MIPS16_CALL16;
}
+static inline bfd_boolean
+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 bfd_boolean
+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 bfd_boolean
+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 bfd_boolean
+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 bfd_boolean
+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);
+}
+
void
-_bfd_mips16_elf_reloc_unshuffle (bfd *abfd, int r_type,
- bfd_boolean jal_shuffle, bfd_byte *data)
+_bfd_mips_elf_reloc_unshuffle (bfd *abfd, int r_type,
+ bfd_boolean jal_shuffle, bfd_byte *data)
{
- bfd_vma extend, insn, val;
+ bfd_vma first, second, val;
- if (!mips16_reloc_p (r_type))
+ if (!mips16_reloc_p (r_type) && !micromips_reloc_shuffle_p (r_type))
return;
- /* Pick up the mips16 extend instruction and the real instruction. */
- extend = bfd_get_16 (abfd, data);
- insn = bfd_get_16 (abfd, data + 2);
- if (r_type == R_MIPS16_26)
- {
- if (jal_shuffle)
- val = ((extend & 0xfc00) << 16) | ((extend & 0x3e0) << 11)
- | ((extend & 0x1f) << 21) | insn;
- else
- val = extend << 16 | insn;
- }
+ /* 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 = ((extend & 0xf800) << 16) | ((insn & 0xffe0) << 11)
- | ((extend & 0x1f) << 11) | (extend & 0x7e0) | (insn & 0x1f);
+ val = (((first & 0xfc00) << 16) | ((first & 0x3e0) << 11)
+ | ((first & 0x1f) << 21) | second);
bfd_put_32 (abfd, val, data);
}
void
-_bfd_mips16_elf_reloc_shuffle (bfd *abfd, int r_type,
- bfd_boolean jal_shuffle, bfd_byte *data)
+_bfd_mips_elf_reloc_shuffle (bfd *abfd, int r_type,
+ bfd_boolean jal_shuffle, bfd_byte *data)
{
- bfd_vma extend, insn, val;
+ bfd_vma first, second, val;
- if (!mips16_reloc_p (r_type))
+ if (!mips16_reloc_p (r_type) && !micromips_reloc_shuffle_p (r_type))
return;
val = bfd_get_32 (abfd, data);
- if (r_type == R_MIPS16_26)
+ if (micromips_reloc_p (r_type) || (r_type == R_MIPS16_26 && !jal_shuffle))
{
- if (jal_shuffle)
- {
- insn = val & 0xffff;
- extend = ((val >> 16) & 0xfc00) | ((val >> 11) & 0x3e0)
- | ((val >> 21) & 0x1f);
- }
- else
- {
- insn = val & 0xffff;
- extend = val >> 16;
- }
+ 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
{
- insn = ((val >> 11) & 0xffe0) | (val & 0x1f);
- extend = ((val >> 16) & 0xf800) | ((val >> 11) & 0x1f) | (val & 0x7e0);
+ second = val & 0xffff;
+ first = ((val >> 16) & 0xfc00) | ((val >> 11) & 0x3e0)
+ | ((val >> 21) & 0x1f);
}
- bfd_put_16 (abfd, insn, data + 2);
- bfd_put_16 (abfd, extend, data);
+ bfd_put_16 (abfd, second, data + 2);
+ bfd_put_16 (abfd, first, data);
}
bfd_reloc_status_type
if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
return bfd_reloc_outofrange;
- _bfd_mips16_elf_reloc_unshuffle (abfd, reloc_entry->howto->type, FALSE,
- location);
- vallo = bfd_get_32 (abfd, location);
- _bfd_mips16_elf_reloc_shuffle (abfd, reloc_entry->howto->type, FALSE,
+ _bfd_mips_elf_reloc_unshuffle (abfd, reloc_entry->howto->type, FALSE,
location);
+ vallo = bfd_get_32 (abfd, location);
+ _bfd_mips_elf_reloc_shuffle (abfd, reloc_entry->howto->type, FALSE,
+ location);
while (mips_hi16_list != NULL)
{
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);
/* VALLO is a signed 16-bit number. Bias it by 0x8000 so that any
carry or borrow will induce a change of +1 or -1 in the high part. */
val += reloc_entry->addend;
/* Add VAL to the relocation field. */
- _bfd_mips16_elf_reloc_unshuffle (abfd, reloc_entry->howto->type, FALSE,
- location);
+ _bfd_mips_elf_reloc_unshuffle (abfd, reloc_entry->howto->type, FALSE,
+ location);
status = _bfd_relocate_contents (reloc_entry->howto, abfd, val,
location);
- _bfd_mips16_elf_reloc_shuffle (abfd, reloc_entry->howto->type, FALSE,
- location);
+ _bfd_mips_elf_reloc_shuffle (abfd, reloc_entry->howto->type, FALSE,
+ location);
if (status != bfd_reloc_ok)
return status;
bfd_boolean strip;
asection *sec, *output_section;
- if (h->root.root.type == bfd_link_hash_warning)
- h = (struct mips_elf_link_hash_entry *) h->root.root.u.i.link;
-
if (h->root.indx == -2)
strip = FALSE;
else if ((h->root.def_dynamic
dname = MIPS_ELF_REL_DYN_NAME (info);
dynobj = elf_hash_table (info)->dynobj;
- sreloc = bfd_get_section_by_name (dynobj, dname);
+ sreloc = bfd_get_linker_section (dynobj, dname);
if (sreloc == NULL && create_p)
{
- sreloc = bfd_make_section_with_flags (dynobj, dname,
- (SEC_ALLOC
- | SEC_LOAD
- | SEC_HAS_CONTENTS
- | SEC_IN_MEMORY
- | SEC_LINKER_CREATED
- | SEC_READONLY));
+ sreloc = bfd_make_section_anyway_with_flags (dynobj, dname,
+ (SEC_ALLOC
+ | SEC_LOAD
+ | SEC_HAS_CONTENTS
+ | SEC_IN_MEMORY
+ | SEC_LINKER_CREATED
+ | SEC_READONLY));
if (sreloc == NULL
|| ! bfd_set_section_alignment (dynobj, sreloc,
MIPS_ELF_LOG_FILE_ALIGN (dynobj)))
bfd_boolean need_relocs = FALSE;
htab = mips_elf_hash_table (info);
+ if (htab == NULL)
+ return;
+
sgot = htab->sgot;
indx = 0;
int r_type, struct bfd_link_info *info,
struct mips_elf_link_hash_entry *h, bfd_vma symbol)
{
- BFD_ASSERT (r_type == R_MIPS_TLS_GOTTPREL || r_type == R_MIPS_TLS_GD
- || r_type == R_MIPS_TLS_LDM);
+ BFD_ASSERT (tls_gottprel_reloc_p (r_type)
+ || tls_gd_reloc_p (r_type)
+ || tls_ldm_reloc_p (r_type));
mips_elf_initialize_tls_slots (abfd, got_index, tls_type, info, h, symbol);
- if (r_type == R_MIPS_TLS_GOTTPREL)
+ if (tls_gottprel_reloc_p (r_type))
{
BFD_ASSERT (*tls_type & GOT_TLS_IE);
if (*tls_type & GOT_TLS_GD)
return got_index;
}
- if (r_type == R_MIPS_TLS_GD)
+ if (tls_gd_reloc_p (r_type))
{
BFD_ASSERT (*tls_type & GOT_TLS_GD);
return got_index;
}
- if (r_type == R_MIPS_TLS_LDM)
+ if (tls_ldm_reloc_p (r_type))
{
BFD_ASSERT (*tls_type & GOT_TLS_LDM);
return got_index;
struct mips_elf_link_hash_table *htab;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
BFD_ASSERT (h->plt.offset != (bfd_vma) -1);
/* This function only works for VxWorks, because a non-VxWorks .got.plt
struct mips_got_entry *entry;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
entry = mips_elf_create_local_got_entry (abfd, info, ibfd, value,
r_symndx, h, r_type);
if (!entry)
long global_got_dynindx = 0;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
gg = g = htab->got_info;
if (g->bfd2got && ibfd)
{
}
/* Find a local GOT entry for an R_MIPS*_GOT16 relocation against VALUE.
- EXTERNAL is true if the relocation was against a global symbol
- that has been forced local. */
+ EXTERNAL is true if the relocation was originally against a global
+ symbol that binds locally. */
static bfd_vma
mips_elf_got16_entry (bfd *abfd, bfd *ibfd, struct bfd_link_info *info,
bfd_vma gp;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
sgot = htab->sgot;
gp = _bfd_get_gp_value (output_bfd)
+ mips_elf_adjust_gp (output_bfd, htab->got_info, input_bfd);
struct mips_elf_link_hash_table *htab;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
entry.abfd = NULL;
entry.symndx = -1;
BFD_ASSERT (g != NULL);
}
- /* We might have a symbol, H, if it has been forced local. Use the
- global entry then. It doesn't matter whether an entry is local
- or global for TLS, since the dynamic linker does not
- automatically relocate TLS GOT entries. */
- BFD_ASSERT (h == NULL || h->root.forced_local);
+ /* This function shouldn't be called for symbols that live in the global
+ area of the GOT. */
+ BFD_ASSERT (h == NULL || h->global_got_area == GGA_NONE);
if (TLS_RELOC_P (r_type))
{
struct mips_got_entry *p;
entry.abfd = ibfd;
- if (r_type == R_MIPS_TLS_LDM)
+ if (tls_ldm_reloc_p (r_type))
{
entry.tls_type = GOT_TLS_LDM;
entry.symndx = 0;
return TRUE;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
g = htab->got_info;
if (g == NULL)
return TRUE;
{
struct mips_elf_hash_sort_data *hsd = data;
- if (h->root.root.type == bfd_link_hash_warning)
- h = (struct mips_elf_link_hash_entry *) h->root.root.u.i.link;
-
/* Symbols without dynamic symbol table entries aren't interesting
at all. */
if (h->root.dynindx == -1)
/* If H is a symbol that needs a global GOT entry, but has a dynamic
symbol table index lower than any we've seen to date, record it for
- posterity. */
+ posterity. FOR_CALL is true if the caller is only interested in
+ using the GOT entry for calls. */
static bfd_boolean
mips_elf_record_global_got_symbol (struct elf_link_hash_entry *h,
bfd *abfd, struct bfd_link_info *info,
+ bfd_boolean for_call,
unsigned char tls_flag)
{
struct mips_elf_link_hash_table *htab;
struct mips_got_info *g;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
hmips = (struct mips_elf_link_hash_entry *) h;
+ if (!for_call)
+ hmips->got_only_for_calls = FALSE;
/* A global symbol in the GOT must also be in the dynamic symbol
table. */
struct mips_got_entry entry, **loc;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
g = htab->got_info;
BFD_ASSERT (g != NULL);
void **loc;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
g = htab->got_info;
BFD_ASSERT (g != NULL);
struct mips_elf_link_hash_table *htab;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
s = mips_elf_rel_dyn_section (info, FALSE);
BFD_ASSERT (s != NULL);
}
/* A mips_elf_link_hash_traverse callback for which DATA points
- to a mips_got_info. Count the number of type (3) entries. */
+ to the link_info structure. Count the number of type (3) entries
+ in the master GOT. */
static int
mips_elf_count_got_symbols (struct mips_elf_link_hash_entry *h, void *data)
{
+ struct bfd_link_info *info;
+ struct mips_elf_link_hash_table *htab;
struct mips_got_info *g;
- g = (struct mips_got_info *) data;
+ info = (struct bfd_link_info *) data;
+ htab = mips_elf_hash_table (info);
+ g = htab->got_info;
if (h->global_got_area != GGA_NONE)
{
- if (h->root.forced_local || h->root.dynindx == -1)
- {
- /* We no longer need this entry if it was only used for
- relocations; those relocations will be against the
- null or section symbol instead of H. */
+ /* Make a final decision about whether the symbol belongs in the
+ local or global GOT. Symbols that bind locally can (and in the
+ case of forced-local symbols, must) live in the local GOT.
+ Those that are aren't in the dynamic symbol table must also
+ live in the local GOT.
+
+ Note that the former condition does not always imply the
+ latter: symbols do not bind locally if they are completely
+ undefined. We'll report undefined symbols later if appropriate. */
+ if (h->root.dynindx == -1
+ || (h->got_only_for_calls
+ ? SYMBOL_CALLS_LOCAL (info, &h->root)
+ : SYMBOL_REFERENCES_LOCAL (info, &h->root)))
+ {
+ /* The symbol belongs in the local GOT. We no longer need this
+ entry if it was only used for relocations; those relocations
+ will be against the null or section symbol instead of H. */
if (h->global_got_area != GGA_RELOC_ONLY)
g->local_gotno++;
h->global_got_area = GGA_NONE;
}
+ else if (htab->is_vxworks
+ && h->got_only_for_calls
+ && h->root.plt.offset != MINUS_ONE)
+ /* On VxWorks, calls can refer directly to the .got.plt entry;
+ they don't need entries in the regular GOT. .got.plt entries
+ will be allocated by _bfd_mips_elf_adjust_dynamic_symbol. */
+ h->global_got_area = GGA_NONE;
else
{
g->global_gotno++;
if (entry->tls_type & GOT_TLS_IE)
g->tls_gotno += 1;
}
- else if (entry->symndx >= 0 || entry->d.h->root.forced_local)
+ else if (entry->symndx >= 0 || entry->d.h->global_got_area == GGA_NONE)
++g->local_gotno;
else
++g->global_gotno;
if (estimate >= from->page_gotno + to->page_gotno)
estimate = from->page_gotno + to->page_gotno;
- /* And conservatively estimate how many local, global and TLS entries
+ /* And conservatively estimate how many local and TLS entries
would be needed. */
- estimate += (from->local_gotno
- + from->global_gotno
- + from->tls_gotno
- + to->local_gotno
- + to->global_gotno
- + to->tls_gotno);
+ estimate += from->local_gotno + to->local_gotno;
+ estimate += from->tls_gotno + to->tls_gotno;
+
+ /* If we're merging with the primary got, we will always have
+ the full set of global entries. Otherwise estimate those
+ conservatively as well. */
+ if (to == arg->primary)
+ estimate += arg->global_count;
+ else
+ estimate += from->global_gotno + to->global_gotno;
/* Bail out if the combined GOT might be too big. */
if (estimate > arg->max_count)
entry = (struct mips_got_entry *) *entryp;
info = (struct bfd_link_info *) data;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
if (entry->abfd != NULL
&& entry->symndx == -1
&& entry->d.h->needs_lazy_stub)
dynobj = elf_hash_table (info)->dynobj;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
g = htab->got_info;
g->bfd2got = htab_try_create (1, mips_elf_bfd2got_entry_hash,
mips_elf_bfd2got_entry_eq, NULL);
return NULL;
}
-/* Return whether a relocation is against a local symbol. */
+/* Return whether an input relocation is against a local symbol. */
static bfd_boolean
mips_elf_local_relocation_p (bfd *input_bfd,
const Elf_Internal_Rela *relocation,
- asection **local_sections,
- bfd_boolean check_forced)
+ asection **local_sections)
{
unsigned long r_symndx;
Elf_Internal_Shdr *symtab_hdr;
- struct mips_elf_link_hash_entry *h;
size_t extsymoff;
r_symndx = ELF_R_SYM (input_bfd, relocation->r_info);
if (elf_bad_symtab (input_bfd) && local_sections[r_symndx] != NULL)
return TRUE;
- if (check_forced)
- {
- /* Look up the hash table to check whether the symbol
- was forced local. */
- h = (struct mips_elf_link_hash_entry *)
- elf_sym_hashes (input_bfd) [r_symndx - extsymoff];
- /* Find the real hash-table entry for this symbol. */
- while (h->root.root.type == bfd_link_hash_indirect
- || h->root.root.type == bfd_link_hash_warning)
- h = (struct mips_elf_link_hash_entry *) h->root.root.u.i.link;
- if (h->root.forced_local)
- return TRUE;
- }
-
return FALSE;
}
\f
flagword flags;
register asection *s;
- if (bfd_get_section_by_name (abfd, ".compact_rel") == NULL)
+ if (bfd_get_linker_section (abfd, ".compact_rel") == NULL)
{
flags = (SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED
| SEC_READONLY);
- s = bfd_make_section_with_flags (abfd, ".compact_rel", flags);
+ s = bfd_make_section_anyway_with_flags (abfd, ".compact_rel", flags);
if (s == NULL
|| ! bfd_set_section_alignment (abfd, s,
MIPS_ELF_LOG_FILE_ALIGN (abfd)))
struct mips_elf_link_hash_table *htab;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
/* This function may be called more than once. */
if (htab->sgot)
/* We have to use an alignment of 2**4 here because this is hardcoded
in the function stub generation and in the linker script. */
- s = bfd_make_section_with_flags (abfd, ".got", flags);
+ s = bfd_make_section_anyway_with_flags (abfd, ".got", flags);
if (s == NULL
|| ! bfd_set_section_alignment (abfd, s, 4))
return FALSE;
|= SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL;
/* We also need a .got.plt section when generating PLTs. */
- s = bfd_make_section_with_flags (abfd, ".got.plt",
- SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
- | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+ s = bfd_make_section_anyway_with_flags (abfd, ".got.plt",
+ SEC_ALLOC | SEC_LOAD
+ | SEC_HAS_CONTENTS
+ | SEC_IN_MEMORY
+ | SEC_LINKER_CREATED);
if (s == NULL)
return FALSE;
htab->sgotplt = s;
stub. */
static bfd_boolean
-mips_elf_relocation_needs_la25_stub (bfd *input_bfd, int r_type)
+mips_elf_relocation_needs_la25_stub (bfd *input_bfd, int r_type,
+ bfd_boolean target_is_16_bit_code_p)
{
/* We specifically ignore branches and jumps from EF_PIC objects,
where the onus is on the compiler or programmer to perform any
{
case R_MIPS_26:
case R_MIPS_PC16:
- case R_MIPS16_26:
+ case R_MICROMIPS_26_S1:
+ case R_MICROMIPS_PC7_S1:
+ case R_MICROMIPS_PC10_S1:
+ case R_MICROMIPS_PC16_S1:
+ case R_MICROMIPS_PC23_S2:
return TRUE;
+ case R_MIPS16_26:
+ return !target_is_16_bit_code_p;
+
default:
return FALSE;
}
RELOCATION; RELOCATION->R_ADDEND is ignored.
The result of the relocation calculation is stored in VALUEP.
- REQUIRE_JALXP indicates whether or not the opcode used with this
- relocation must be JALX.
+ On exit, set *CROSS_MODE_JUMP_P to true if the relocation field
+ is a MIPS16 or microMIPS jump to standard MIPS code, or vice versa.
This function returns bfd_reloc_continue if the caller need take no
further action regarding this relocation, bfd_reloc_notsupported if
bfd_vma addend, reloc_howto_type *howto,
Elf_Internal_Sym *local_syms,
asection **local_sections, bfd_vma *valuep,
- const char **namep, bfd_boolean *require_jalxp,
+ const char **namep,
+ bfd_boolean *cross_mode_jump_p,
bfd_boolean save_addend)
{
/* The eventual value we will return. */
bfd_boolean overflowed_p;
/* TRUE if this relocation refers to a MIPS16 function. */
bfd_boolean target_is_16_bit_code_p = FALSE;
+ bfd_boolean target_is_micromips_code_p = FALSE;
struct mips_elf_link_hash_table *htab;
bfd *dynobj;
dynobj = elf_hash_table (info)->dynobj;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
/* Parse the relocation. */
r_symndx = ELF_R_SYM (input_bfd, relocation->r_info);
used in the array of hash table entries. */
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
local_p = mips_elf_local_relocation_p (input_bfd, relocation,
- local_sections, FALSE);
+ local_sections);
was_local_p = local_p;
if (! elf_bad_symtab (input_bfd))
extsymoff = symtab_hdr->sh_info;
addend += sec->output_section->vma + sec->output_offset;
}
- /* MIPS16 text labels should be treated as odd. */
- if (ELF_ST_IS_MIPS16 (sym->st_other))
+ /* MIPS16/microMIPS text labels should be treated as odd. */
+ if (ELF_ST_IS_COMPRESSED (sym->st_other))
++symbol;
/* Record the name of this symbol, for our caller. */
*namep = bfd_section_name (input_bfd, sec);
target_is_16_bit_code_p = ELF_ST_IS_MIPS16 (sym->st_other);
+ target_is_micromips_code_p = ELF_ST_IS_MICROMIPS (sym->st_other);
}
else
{
}
target_is_16_bit_code_p = ELF_ST_IS_MIPS16 (h->root.other);
+ /* If the output section is the PLT section,
+ then the target is not microMIPS. */
+ target_is_micromips_code_p = (htab->splt != sec
+ && ELF_ST_IS_MICROMIPS (h->root.other));
}
/* If this is a reference to a 16-bit function with a stub, we need
have already noticed that we were going to need the
stub. */
if (local_p)
- sec = elf_tdata (input_bfd)->local_stubs[r_symndx];
+ {
+ sec = elf_tdata (input_bfd)->local_stubs[r_symndx];
+ value = 0;
+ }
else
{
BFD_ASSERT (h->need_fn_stub);
- sec = h->fn_stub;
+ if (h->la25_stub)
+ {
+ /* If a LA25 header for the stub itself exists, point to the
+ prepended LUI/ADDIU sequence. */
+ sec = h->la25_stub->stub_section;
+ value = h->la25_stub->offset;
+ }
+ else
+ {
+ sec = h->fn_stub;
+ value = 0;
+ }
}
- symbol = sec->output_section->vma + sec->output_offset;
+ symbol = sec->output_section->vma + sec->output_offset + value;
/* The target is 16-bit, but the stub isn't. */
target_is_16_bit_code_p = FALSE;
}
/* If this is a direct call to a PIC function, redirect to the
non-PIC stub. */
else if (h != NULL && h->la25_stub
- && mips_elf_relocation_needs_la25_stub (input_bfd, r_type))
+ && mips_elf_relocation_needs_la25_stub (input_bfd, r_type,
+ target_is_16_bit_code_p))
symbol = (h->la25_stub->stub_section->output_section->vma
+ h->la25_stub->stub_section->output_offset
+ h->la25_stub->offset);
- /* Calls from 16-bit code to 32-bit code and vice versa require the
- special jalx instruction. */
- *require_jalxp = (!info->relocatable
- && (((r_type == R_MIPS16_26) && !target_is_16_bit_code_p)
- || ((r_type == R_MIPS_26) && target_is_16_bit_code_p)));
+ /* Make sure MIPS16 and microMIPS are not used together. */
+ if ((r_type == R_MIPS16_26 && target_is_micromips_code_p)
+ || (micromips_branch_reloc_p (r_type) && target_is_16_bit_code_p))
+ {
+ (*_bfd_error_handler)
+ (_("MIPS16 and microMIPS functions cannot call each other"));
+ return bfd_reloc_notsupported;
+ }
- local_p = mips_elf_local_relocation_p (input_bfd, relocation,
- local_sections, TRUE);
+ /* Calls from 16-bit code to 32-bit code and vice versa require the
+ mode change. However, we can ignore calls to undefined weak symbols,
+ which should never be executed at runtime. This exception is important
+ because the assembly writer may have "known" that any definition of the
+ symbol would be 16-bit code, and that direct jumps were therefore
+ acceptable. */
+ *cross_mode_jump_p = (!info->relocatable
+ && !(h && h->root.root.type == bfd_link_hash_undefweak)
+ && ((r_type == R_MIPS16_26 && !target_is_16_bit_code_p)
+ || (r_type == R_MICROMIPS_26_S1
+ && !target_is_micromips_code_p)
+ || ((r_type == R_MIPS_26 || r_type == R_MIPS_JALR)
+ && (target_is_16_bit_code_p
+ || target_is_micromips_code_p))));
+
+ local_p = (h == NULL
+ || (h->got_only_for_calls
+ ? SYMBOL_CALLS_LOCAL (info, &h->root)
+ : SYMBOL_REFERENCES_LOCAL (info, &h->root)));
gp0 = _bfd_get_gp_value (input_bfd);
gp = _bfd_get_gp_value (abfd);
if (gnu_local_gp_p)
symbol = gp;
- /* If we haven't already determined the GOT offset, oand we're going
+ /* Global R_MIPS_GOT_PAGE/R_MICROMIPS_GOT_PAGE relocations are equivalent
+ to R_MIPS_GOT_DISP/R_MICROMIPS_GOT_DISP. The addend is applied by the
+ corresponding R_MIPS_GOT_OFST/R_MICROMIPS_GOT_OFST. */
+ if (got_page_reloc_p (r_type) && !local_p)
+ {
+ r_type = (micromips_reloc_p (r_type)
+ ? R_MICROMIPS_GOT_DISP : R_MIPS_GOT_DISP);
+ addend = 0;
+ }
+
+ /* If we haven't already determined the GOT offset, and we're going
to need it, get it now. */
switch (r_type)
{
- case R_MIPS_GOT_PAGE:
- case R_MIPS_GOT_OFST:
- /* We need to decay to GOT_DISP/addend if the symbol doesn't
- bind locally. */
- local_p = local_p || _bfd_elf_symbol_refs_local_p (&h->root, info, 1);
- if (local_p || r_type == R_MIPS_GOT_OFST)
- break;
- /* Fall through. */
-
case R_MIPS16_CALL16:
case R_MIPS16_GOT16:
case R_MIPS_CALL16:
case R_MIPS_CALL_HI16:
case R_MIPS_GOT_LO16:
case R_MIPS_CALL_LO16:
+ case R_MICROMIPS_CALL16:
+ case R_MICROMIPS_GOT16:
+ case R_MICROMIPS_GOT_DISP:
+ case R_MICROMIPS_GOT_HI16:
+ case R_MICROMIPS_CALL_HI16:
+ case R_MICROMIPS_GOT_LO16:
+ case R_MICROMIPS_CALL_LO16:
case R_MIPS_TLS_GD:
case R_MIPS_TLS_GOTTPREL:
case R_MIPS_TLS_LDM:
+ case R_MIPS16_TLS_GD:
+ case R_MIPS16_TLS_GOTTPREL:
+ case R_MIPS16_TLS_LDM:
+ case R_MICROMIPS_TLS_GD:
+ case R_MICROMIPS_TLS_GOTTPREL:
+ case R_MICROMIPS_TLS_LDM:
/* Find the index into the GOT where this value is located. */
- if (r_type == R_MIPS_TLS_LDM)
+ if (tls_ldm_reloc_p (r_type))
{
g = mips_elf_local_got_index (abfd, input_bfd, info,
0, 0, NULL, r_type);
/* On VxWorks, CALL relocations should refer to the .got.plt
entry, which is initialized to point at the PLT stub. */
if (htab->is_vxworks
- && (r_type == R_MIPS_CALL_HI16
- || r_type == R_MIPS_CALL_LO16
+ && (call_hi16_reloc_p (r_type)
+ || call_lo16_reloc_p (r_type)
|| call16_reloc_p (r_type)))
{
BFD_ASSERT (addend == 0);
}
else
{
- /* GOT_PAGE may take a non-zero addend, that is ignored in a
- GOT_PAGE relocation that decays to GOT_DISP because the
- symbol turns out to be global. The addend is then added
- as GOT_OFST. */
- BFD_ASSERT (addend == 0 || r_type == R_MIPS_GOT_PAGE);
+ BFD_ASSERT (addend == 0);
g = mips_elf_global_got_index (dynobj, input_bfd,
&h->root, r_type, info);
if (h->tls_type == GOT_NORMAL
- && (! elf_hash_table(info)->dynamic_sections_created
- || (info->shared
- && (info->symbolic || h->root.forced_local)
- && h->root.def_regular)))
- /* This is a static link or a -Bsymbolic link. The
- symbol is defined locally, or was forced to be local.
- We must initialize this entry in the GOT. */
+ && !elf_hash_table (info)->dynamic_sections_created)
+ /* This is a static link. We must initialize the GOT entry. */
MIPS_ELF_PUT_WORD (dynobj, symbol, htab->sgot->contents + g);
}
}
&& h->root.def_dynamic
&& !h->root.def_regular
&& !h->has_static_relocs))
- && r_symndx != 0
+ && r_symndx != STN_UNDEF
&& (h == NULL
|| h->root.root.type != bfd_link_hash_undefweak
|| ELF_ST_VISIBILITY (h->root.other) == STV_DEFAULT)
mips_elf_perform_relocation. So, we just fall through to the
R_MIPS_26 case here. */
case R_MIPS_26:
- if (local_p)
- value = ((addend | ((p + 4) & 0xf0000000)) + symbol) >> 2;
- else
- {
- value = (_bfd_mips_elf_sign_extend (addend, 28) + symbol) >> 2;
- if (h->root.root.type != bfd_link_hash_undefweak)
- overflowed_p = (value >> 26) != ((p + 4) >> 28);
- }
- value &= howto->dst_mask;
+ case R_MICROMIPS_26_S1:
+ {
+ unsigned int shift;
+
+ /* Make sure the target of JALX is word-aligned. Bit 0 must be
+ the correct ISA mode selector and bit 1 must be 0. */
+ if (*cross_mode_jump_p && (symbol & 3) != (r_type == R_MIPS_26))
+ return bfd_reloc_outofrange;
+
+ /* Shift is 2, unusually, for microMIPS JALX. */
+ shift = (!*cross_mode_jump_p && r_type == R_MICROMIPS_26_S1) ? 1 : 2;
+
+ if (was_local_p)
+ value = addend | ((p + 4) & (0xfc000000 << shift));
+ else
+ value = _bfd_mips_elf_sign_extend (addend, 26 + shift);
+ value = (value + symbol) >> shift;
+ if (!was_local_p && h->root.root.type != bfd_link_hash_undefweak)
+ overflowed_p = (value >> 26) != ((p + 4) >> (26 + shift));
+ value &= howto->dst_mask;
+ }
break;
case R_MIPS_TLS_DTPREL_HI16:
+ case R_MIPS16_TLS_DTPREL_HI16:
+ case R_MICROMIPS_TLS_DTPREL_HI16:
value = (mips_elf_high (addend + symbol - dtprel_base (info))
& howto->dst_mask);
break;
case R_MIPS_TLS_DTPREL_LO16:
case R_MIPS_TLS_DTPREL32:
case R_MIPS_TLS_DTPREL64:
+ case R_MIPS16_TLS_DTPREL_LO16:
+ case R_MICROMIPS_TLS_DTPREL_LO16:
value = (symbol + addend - dtprel_base (info)) & howto->dst_mask;
break;
case R_MIPS_TLS_TPREL_HI16:
+ case R_MIPS16_TLS_TPREL_HI16:
+ case R_MICROMIPS_TLS_TPREL_HI16:
value = (mips_elf_high (addend + symbol - tprel_base (info))
& howto->dst_mask);
break;
case R_MIPS_TLS_TPREL_LO16:
+ case R_MIPS_TLS_TPREL32:
+ case R_MIPS_TLS_TPREL64:
+ case R_MIPS16_TLS_TPREL_LO16:
+ case R_MICROMIPS_TLS_TPREL_LO16:
value = (symbol + addend - tprel_base (info)) & howto->dst_mask;
break;
case R_MIPS_HI16:
case R_MIPS16_HI16:
+ case R_MICROMIPS_HI16:
if (!gp_disp_p)
{
value = mips_elf_high (addend + symbol);
12: addu $v0,$v1
14: move $gp,$v0
So the offsets of hi and lo relocs are the same, but the
- $pc is four higher than $t9 would be, so reduce
- both reloc addends by 4. */
+ base $pc is that used by the ADDIUPC instruction at $t9 + 4.
+ ADDIUPC clears the low two bits of the instruction address,
+ so the base is ($t9 + 4) & ~3. */
if (r_type == R_MIPS16_HI16)
- value = mips_elf_high (addend + gp - p - 4);
+ value = mips_elf_high (addend + gp - ((p + 4) & ~(bfd_vma) 0x3));
+ /* The microMIPS .cpload sequence uses the same assembly
+ instructions as the traditional psABI version, but the
+ incoming $t9 has the low bit set. */
+ else if (r_type == R_MICROMIPS_HI16)
+ value = mips_elf_high (addend + gp - p - 1);
else
value = mips_elf_high (addend + gp - p);
overflowed_p = mips_elf_overflow_p (value, 16);
case R_MIPS_LO16:
case R_MIPS16_LO16:
+ case R_MICROMIPS_LO16:
+ case R_MICROMIPS_HI0_LO16:
if (!gp_disp_p)
value = (symbol + addend) & howto->dst_mask;
else
/* See the comment for R_MIPS16_HI16 above for the reason
for this conditional. */
if (r_type == R_MIPS16_LO16)
- value = addend + gp - p;
+ value = addend + gp - (p & ~(bfd_vma) 0x3);
+ else if (r_type == R_MICROMIPS_LO16
+ || r_type == R_MICROMIPS_HI0_LO16)
+ value = addend + gp - p + 3;
else
value = addend + gp - p + 4;
/* The MIPS ABI requires checking the R_MIPS_LO16 relocation
break;
case R_MIPS_LITERAL:
+ case R_MICROMIPS_LITERAL:
/* Because we don't merge literal sections, we can handle this
just like R_MIPS_GPREL16. In the long run, we should merge
shared literals, and then we will need to additional work
order. We don't need to do anything special here; the
differences are handled in mips_elf_perform_relocation. */
case R_MIPS_GPREL16:
+ case R_MICROMIPS_GPREL7_S2:
+ case R_MICROMIPS_GPREL16:
/* Only sign-extend the addend if it was extracted from the
instruction. If the addend was separate, leave it alone,
otherwise we may lose significant bits. */
case R_MIPS16_CALL16:
case R_MIPS_GOT16:
case R_MIPS_CALL16:
+ case R_MICROMIPS_GOT16:
+ case R_MICROMIPS_CALL16:
/* VxWorks does not have separate local and global semantics for
R_MIPS*_GOT16; every relocation evaluates to "G". */
if (!htab->is_vxworks && local_p)
{
- bfd_boolean forced;
-
- forced = ! mips_elf_local_relocation_p (input_bfd, relocation,
- local_sections, FALSE);
value = mips_elf_got16_entry (abfd, input_bfd, info,
- symbol + addend, forced);
+ symbol + addend, !was_local_p);
if (value == MINUS_ONE)
return bfd_reloc_outofrange;
value
case R_MIPS_TLS_GOTTPREL:
case R_MIPS_TLS_LDM:
case R_MIPS_GOT_DISP:
- got_disp:
+ case R_MIPS16_TLS_GD:
+ case R_MIPS16_TLS_GOTTPREL:
+ case R_MIPS16_TLS_LDM:
+ case R_MICROMIPS_TLS_GD:
+ case R_MICROMIPS_TLS_GOTTPREL:
+ case R_MICROMIPS_TLS_LDM:
+ case R_MICROMIPS_GOT_DISP:
value = g;
overflowed_p = mips_elf_overflow_p (value, 16);
break;
value &= howto->dst_mask;
break;
+ case R_MICROMIPS_PC7_S1:
+ value = symbol + _bfd_mips_elf_sign_extend (addend, 8) - p;
+ overflowed_p = mips_elf_overflow_p (value, 8);
+ value >>= howto->rightshift;
+ value &= howto->dst_mask;
+ break;
+
+ case R_MICROMIPS_PC10_S1:
+ value = symbol + _bfd_mips_elf_sign_extend (addend, 11) - p;
+ overflowed_p = mips_elf_overflow_p (value, 11);
+ value >>= howto->rightshift;
+ value &= howto->dst_mask;
+ break;
+
+ case R_MICROMIPS_PC16_S1:
+ value = symbol + _bfd_mips_elf_sign_extend (addend, 17) - p;
+ overflowed_p = mips_elf_overflow_p (value, 17);
+ value >>= howto->rightshift;
+ value &= howto->dst_mask;
+ break;
+
+ case R_MICROMIPS_PC23_S2:
+ value = symbol + _bfd_mips_elf_sign_extend (addend, 25) - ((p | 3) ^ 3);
+ overflowed_p = mips_elf_overflow_p (value, 25);
+ value >>= howto->rightshift;
+ value &= howto->dst_mask;
+ break;
+
case R_MIPS_GOT_HI16:
case R_MIPS_CALL_HI16:
+ case R_MICROMIPS_GOT_HI16:
+ case R_MICROMIPS_CALL_HI16:
/* We're allowed to handle these two relocations identically.
The dynamic linker is allowed to handle the CALL relocations
differently by creating a lazy evaluation stub. */
case R_MIPS_GOT_LO16:
case R_MIPS_CALL_LO16:
+ case R_MICROMIPS_GOT_LO16:
+ case R_MICROMIPS_CALL_LO16:
value = g & howto->dst_mask;
break;
case R_MIPS_GOT_PAGE:
- /* GOT_PAGE relocations that reference non-local symbols decay
- to GOT_DISP. The corresponding GOT_OFST relocation decays to
- 0. */
- if (! local_p)
- goto got_disp;
+ case R_MICROMIPS_GOT_PAGE:
value = mips_elf_got_page (abfd, input_bfd, info, symbol + addend, NULL);
if (value == MINUS_ONE)
return bfd_reloc_outofrange;
break;
case R_MIPS_GOT_OFST:
+ case R_MICROMIPS_GOT_OFST:
if (local_p)
mips_elf_got_page (abfd, input_bfd, info, symbol + addend, &value);
else
break;
case R_MIPS_SUB:
+ case R_MICROMIPS_SUB:
value = symbol - addend;
value &= howto->dst_mask;
break;
case R_MIPS_HIGHER:
+ case R_MICROMIPS_HIGHER:
value = mips_elf_higher (addend + symbol);
value &= howto->dst_mask;
break;
case R_MIPS_HIGHEST:
+ case R_MICROMIPS_HIGHEST:
value = mips_elf_highest (addend + symbol);
value &= howto->dst_mask;
break;
case R_MIPS_SCN_DISP:
+ case R_MICROMIPS_SCN_DISP:
value = symbol + addend - sec->output_offset;
value &= howto->dst_mask;
break;
case R_MIPS_JALR:
+ case R_MICROMIPS_JALR:
/* This relocation is only a hint. In some cases, we optimize
it into a bal instruction. But we don't try to optimize
when the symbol does not resolve locally. */
/* It has been determined that the result of the RELOCATION is the
VALUE. Use HOWTO to place VALUE into the output file at the
appropriate position. The SECTION is the section to which the
- relocation applies. If REQUIRE_JALX is TRUE, then the opcode used
- for the relocation must be either JAL or JALX, and it is
- unconditionally converted to JALX.
+ relocation applies.
+ CROSS_MODE_JUMP_P is true if the relocation field
+ is a MIPS16 or microMIPS jump to standard MIPS code, or vice versa.
Returns FALSE if anything goes wrong. */
const Elf_Internal_Rela *relocation,
bfd_vma value, bfd *input_bfd,
asection *input_section, bfd_byte *contents,
- bfd_boolean require_jalx)
+ bfd_boolean cross_mode_jump_p)
{
bfd_vma x;
bfd_byte *location;
/* Figure out where the relocation is occurring. */
location = contents + relocation->r_offset;
- _bfd_mips16_elf_reloc_unshuffle (input_bfd, r_type, FALSE, location);
+ _bfd_mips_elf_reloc_unshuffle (input_bfd, r_type, FALSE, location);
/* Obtain the current value. */
x = mips_elf_obtain_contents (howto, relocation, input_bfd, contents);
x |= (value & howto->dst_mask);
/* If required, turn JAL into JALX. */
- if (require_jalx)
+ if (cross_mode_jump_p && jal_reloc_p (r_type))
{
bfd_boolean ok;
bfd_vma opcode = x >> 26;
ok = ((opcode == 0x6) || (opcode == 0x7));
jalx_opcode = 0x7;
}
+ else if (r_type == R_MICROMIPS_26_S1)
+ {
+ ok = ((opcode == 0x3d) || (opcode == 0x3c));
+ jalx_opcode = 0x3c;
+ }
else
{
ok = ((opcode == 0x3) || (opcode == 0x1d));
jalx_opcode = 0x1d;
}
- /* If the opcode is not JAL or JALX, there's a problem. */
+ /* If the opcode is not JAL or JALX, there's a problem. We cannot
+ convert J or JALS to JALX. */
if (!ok)
{
(*_bfd_error_handler)
- (_("%B: %A+0x%lx: jump to stub routine which is not jal"),
+ (_("%B: %A+0x%lx: Unsupported jump between ISA modes; consider recompiling with interlinking enabled."),
input_bfd,
input_section,
(unsigned long) relocation->r_offset);
x = (x & ~(0x3f << 26)) | (jalx_opcode << 26);
}
- /* Try converting JAL and JALR to BAL, if the target is in range. */
+ /* Try converting JAL to BAL and J(AL)R to B(AL), if the target is in
+ range. */
if (!info->relocatable
- && !require_jalx
+ && !cross_mode_jump_p
&& ((JAL_TO_BAL_P (input_bfd)
&& r_type == R_MIPS_26
&& (x >> 26) == 0x3) /* jal addr */
|| (JALR_TO_BAL_P (input_bfd)
&& r_type == R_MIPS_JALR
- && x == 0x0320f809))) /* jalr t9 */
+ && x == 0x0320f809) /* jalr t9 */
+ || (JR_TO_B_P (input_bfd)
+ && r_type == R_MIPS_JALR
+ && x == 0x03200008))) /* jr t9 */
{
bfd_vma addr;
bfd_vma dest;
dest = value;
off = dest - addr;
if (off <= 0x1ffff && off >= -0x20000)
- x = 0x04110000 | (((bfd_vma) off >> 2) & 0xffff); /* bal addr */
+ {
+ if (x == 0x03200008) /* jr t9 */
+ x = 0x10000000 | (((bfd_vma) off >> 2) & 0xffff); /* b addr */
+ else
+ x = 0x04110000 | (((bfd_vma) off >> 2) & 0xffff); /* bal addr */
+ }
}
/* Put the value into the output. */
bfd_put (8 * bfd_get_reloc_size (howto), input_bfd, x, location);
- _bfd_mips16_elf_reloc_shuffle(input_bfd, r_type, !info->relocatable,
- location);
+ _bfd_mips_elf_reloc_shuffle (input_bfd, r_type, !info->relocatable,
+ location);
return TRUE;
}
struct mips_elf_link_hash_table *htab;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
r_type = ELF_R_TYPE (output_bfd, rel->r_info);
dynobj = elf_hash_table (info)->dynobj;
sreloc = mips_elf_rel_dyn_section (info, FALSE);
/* We must now calculate the dynamic symbol table index to use
in the relocation. */
- if (h != NULL
- && (!h->root.def_regular
- || (info->shared && !info->symbolic && !h->root.forced_local)))
+ if (h != NULL && ! SYMBOL_REFERENCES_LOCAL (info, &h->root))
{
+ BFD_ASSERT (htab->is_vxworks || h->global_got_area != GGA_NONE);
indx = h->root.dynindx;
if (SGI_COMPAT (output_bfd))
defined_p = h->root.def_regular;
/* On IRIX5, make an entry of compact relocation info. */
if (IRIX_COMPAT (output_bfd) == ict_irix5)
{
- asection *scpt = bfd_get_section_by_name (dynobj, ".compact_rel");
+ asection *scpt = bfd_get_linker_section (dynobj, ".compact_rel");
bfd_byte *cr;
if (scpt)
case E_MIPS_MACH_LS2F:
return bfd_mach_mips_loongson_2f;
+ case E_MIPS_MACH_LS3A:
+ return bfd_mach_mips_loongson_3a;
+
+ case E_MIPS_MACH_OCTEON2:
+ return bfd_mach_mips_octeon2;
+
case E_MIPS_MACH_OCTEON:
return bfd_mach_mips_octeon;
{
asection *section = bfd_get_section_by_name (abfd, ".text");
- BFD_ASSERT (SGI_COMPAT (abfd));
if (section != NULL)
{
asym->section = section;
{
asection *section = bfd_get_section_by_name (abfd, ".data");
- BFD_ASSERT (SGI_COMPAT (abfd));
if (section != NULL)
{
asym->section = section;
break;
}
- /* If this is an odd-valued function symbol, assume it's a MIPS16 one. */
+ /* If this is an odd-valued function symbol, assume it's a MIPS16
+ or microMIPS one. */
if (ELF_ST_TYPE (elfsym->internal_elf_sym.st_info) == STT_FUNC
&& (asym->value & 1) != 0)
{
asym->value--;
- elfsym->internal_elf_sym.st_other
- = ELF_ST_SET_MIPS16 (elfsym->internal_elf_sym.st_other);
+ if (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_MICROMIPS)
+ elfsym->internal_elf_sym.st_other
+ = ELF_ST_SET_MICROMIPS (elfsym->internal_elf_sym.st_other);
+ else
+ elfsym->internal_elf_sym.st_other
+ = ELF_ST_SET_MIPS16 (elfsym->internal_elf_sym.st_other);
}
}
\f
return FALSE;
mips_elf_hash_table (info)->use_rld_obj_head = TRUE;
+ mips_elf_hash_table (info)->rld_symbol = h;
}
/* If this is a mips16 text symbol, add 1 to the value to make it
odd. This will cause something like .word SYM to come up with
the right value when it is loaded into the PC. */
- if (ELF_ST_IS_MIPS16 (sym->st_other))
+ if (ELF_ST_IS_COMPRESSED (sym->st_other))
++*valp;
return TRUE;
&& strcmp (input_sec->name, ".scommon") == 0)
sym->st_shndx = SHN_MIPS_SCOMMON;
- if (ELF_ST_IS_MIPS16 (sym->st_other))
+ if (ELF_ST_IS_COMPRESSED (sym->st_other))
sym->st_value &= ~1;
return 1;
struct mips_elf_link_hash_table *htab;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
| SEC_LINKER_CREATED | SEC_READONLY);
EABI doesn't. */
if (!htab->is_vxworks)
{
- s = bfd_get_section_by_name (abfd, ".dynamic");
+ s = bfd_get_linker_section (abfd, ".dynamic");
if (s != NULL)
{
if (! bfd_set_section_flags (abfd, s, flags))
return FALSE;
/* Create .stub section. */
- s = bfd_make_section_with_flags (abfd,
- MIPS_ELF_STUB_SECTION_NAME (abfd),
- flags | SEC_CODE);
+ s = bfd_make_section_anyway_with_flags (abfd,
+ MIPS_ELF_STUB_SECTION_NAME (abfd),
+ flags | SEC_CODE);
if (s == NULL
|| ! bfd_set_section_alignment (abfd, s,
MIPS_ELF_LOG_FILE_ALIGN (abfd)))
if ((IRIX_COMPAT (abfd) == ict_irix5 || IRIX_COMPAT (abfd) == ict_none)
&& !info->shared
- && bfd_get_section_by_name (abfd, ".rld_map") == NULL)
+ && bfd_get_linker_section (abfd, ".rld_map") == NULL)
{
- s = bfd_make_section_with_flags (abfd, ".rld_map",
- flags &~ (flagword) SEC_READONLY);
+ s = bfd_make_section_anyway_with_flags (abfd, ".rld_map",
+ flags &~ (flagword) SEC_READONLY);
if (s == NULL
|| ! bfd_set_section_alignment (abfd, s,
MIPS_ELF_LOG_FILE_ALIGN (abfd)))
}
/* Change alignments of some sections. */
- s = bfd_get_section_by_name (abfd, ".hash");
+ s = bfd_get_linker_section (abfd, ".hash");
if (s != NULL)
bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
- s = bfd_get_section_by_name (abfd, ".dynsym");
+ s = bfd_get_linker_section (abfd, ".dynsym");
if (s != NULL)
bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
- s = bfd_get_section_by_name (abfd, ".dynstr");
+ s = bfd_get_linker_section (abfd, ".dynstr");
if (s != NULL)
bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
+ /* ??? */
s = bfd_get_section_by_name (abfd, ".reginfo");
if (s != NULL)
bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
- s = bfd_get_section_by_name (abfd, ".dynamic");
+ s = bfd_get_linker_section (abfd, ".dynamic");
if (s != NULL)
bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
}
and is filled in by the rtld to contain a pointer to
the _r_debug structure. Its symbol value will be set in
_bfd_mips_elf_finish_dynamic_symbol. */
- s = bfd_get_section_by_name (abfd, ".rld_map");
+ s = bfd_get_linker_section (abfd, ".rld_map");
BFD_ASSERT (s != NULL);
name = SGI_COMPAT (abfd) ? "__rld_map" : "__RLD_MAP";
if (! bfd_elf_link_record_dynamic_symbol (info, h))
return FALSE;
+ mips_elf_hash_table (info)->rld_symbol = h;
}
}
return FALSE;
/* Cache the sections created above. */
- htab->splt = bfd_get_section_by_name (abfd, ".plt");
- htab->sdynbss = bfd_get_section_by_name (abfd, ".dynbss");
+ htab->splt = bfd_get_linker_section (abfd, ".plt");
+ htab->sdynbss = bfd_get_linker_section (abfd, ".dynbss");
if (htab->is_vxworks)
{
- htab->srelbss = bfd_get_section_by_name (abfd, ".rela.bss");
- htab->srelplt = bfd_get_section_by_name (abfd, ".rela.plt");
+ htab->srelbss = bfd_get_linker_section (abfd, ".rela.bss");
+ htab->srelplt = bfd_get_linker_section (abfd, ".rela.plt");
}
else
- htab->srelplt = bfd_get_section_by_name (abfd, ".rel.plt");
+ htab->srelplt = bfd_get_linker_section (abfd, ".rel.plt");
if (!htab->sdynbss
|| (htab->is_vxworks && !htab->srelbss && !info->shared)
|| !htab->srelplt
Elf_Internal_Shdr *rel_hdr;
const struct elf_backend_data *bed;
- /* To determine which flavor or relocation this is, we depend on the
- fact that the INPUT_SECTION's REL_HDR is read before its REL_HDR2. */
- rel_hdr = &elf_section_data (sec)->rel_hdr;
+ /* To determine which flavor of relocation this is, we depend on the
+ fact that the INPUT_SECTION's REL_HDR is read before RELA_HDR. */
+ rel_hdr = elf_section_data (sec)->rel.hdr;
+ if (rel_hdr == NULL)
+ return FALSE;
bed = get_elf_backend_data (abfd);
- if ((size_t) (rel - relocs)
- >= (NUM_SHDR_ENTRIES (rel_hdr) * bed->s->int_rels_per_ext_rel))
- rel_hdr = elf_section_data (sec)->rel_hdr2;
- return rel_hdr->sh_entsize == MIPS_ELF_REL_SIZE (abfd);
+ return ((size_t) (rel - relocs)
+ < NUM_SHDR_ENTRIES (rel_hdr) * bed->s->int_rels_per_ext_rel);
}
/* Read the addend for REL relocation REL, which belongs to bfd ABFD.
location = contents + rel->r_offset;
/* Get the addend, which is stored in the input file. */
- _bfd_mips16_elf_reloc_unshuffle (abfd, r_type, FALSE, location);
+ _bfd_mips_elf_reloc_unshuffle (abfd, r_type, FALSE, location);
addend = mips_elf_obtain_contents (howto, rel, abfd, contents);
- _bfd_mips16_elf_reloc_shuffle (abfd, r_type, FALSE, location);
+ _bfd_mips_elf_reloc_shuffle (abfd, r_type, FALSE, location);
return addend & howto->src_mask;
}
r_type = ELF_R_TYPE (abfd, rel->r_info);
if (mips16_reloc_p (r_type))
lo16_type = R_MIPS16_LO16;
+ else if (micromips_reloc_p (r_type))
+ lo16_type = R_MICROMIPS_LO16;
else
lo16_type = R_MIPS_LO16;
return TRUE;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
dynobj = elf_hash_table (info)->dynobj;
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
sym_hashes = elf_sym_hashes (abfd);
/* Look at the relocation information to figure out which symbol
this is for. */
- r_symndx = mips16_stub_symndx (sec, relocs, rel_end);
+ r_symndx = mips16_stub_symndx (bed, sec, relocs, rel_end);
if (r_symndx == 0)
{
(*_bfd_error_handler)
/* Look at the relocation information to figure out which symbol
this is for. */
- r_symndx = mips16_stub_symndx (sec, relocs, rel_end);
+ r_symndx = mips16_stub_symndx (bed, sec, relocs, rel_end);
if (r_symndx == 0)
{
(*_bfd_error_handler)
can_make_dynamic_p = FALSE;
switch (r_type)
{
- case R_MIPS16_GOT16:
- case R_MIPS16_CALL16:
case R_MIPS_GOT16:
case R_MIPS_CALL16:
case R_MIPS_CALL_HI16:
case R_MIPS_TLS_GOTTPREL:
case R_MIPS_TLS_GD:
case R_MIPS_TLS_LDM:
+ case R_MIPS16_GOT16:
+ case R_MIPS16_CALL16:
+ case R_MIPS16_TLS_GOTTPREL:
+ case R_MIPS16_TLS_GD:
+ case R_MIPS16_TLS_LDM:
+ case R_MICROMIPS_GOT16:
+ case R_MICROMIPS_CALL16:
+ case R_MICROMIPS_CALL_HI16:
+ case R_MICROMIPS_CALL_LO16:
+ case R_MICROMIPS_GOT_HI16:
+ case R_MICROMIPS_GOT_LO16:
+ case R_MICROMIPS_GOT_PAGE:
+ case R_MICROMIPS_GOT_OFST:
+ case R_MICROMIPS_GOT_DISP:
+ case R_MICROMIPS_TLS_GOTTPREL:
+ case R_MICROMIPS_TLS_GD:
+ case R_MICROMIPS_TLS_LDM:
if (dynobj == NULL)
elf_hash_table (info)->dynobj = dynobj = abfd;
if (!mips_elf_create_got_section (dynobj, info))
/* This is just a hint; it can safely be ignored. Don't set
has_static_relocs for the corresponding symbol. */
case R_MIPS_JALR:
+ case R_MICROMIPS_JALR:
break;
case R_MIPS_32:
elf_hash_table (info)->dynobj = dynobj = abfd;
break;
}
+ /* For sections that are not SEC_ALLOC a copy reloc would be
+ output if possible (implying questionable semantics for
+ read-only data objects) or otherwise the final link would
+ fail as ld.so will not process them and could not therefore
+ handle any outstanding dynamic relocations.
+
+ For such sections that are also SEC_DEBUGGING, we can avoid
+ these problems by simply ignoring any relocs as these
+ sections have a predefined use and we know it is safe to do
+ so.
+
+ This is needed in cases such as a global symbol definition
+ in a shared library causing a common symbol from an object
+ file to be converted to an undefined reference. If that
+ happens, then all the relocations against this symbol from
+ SEC_DEBUGGING sections in the object file will resolve to
+ nil. */
+ if ((sec->flags & SEC_DEBUGGING) != 0)
+ break;
/* Fall through. */
default:
case R_MIPS_26:
case R_MIPS_PC16:
case R_MIPS16_26:
+ case R_MICROMIPS_26_S1:
+ case R_MICROMIPS_PC7_S1:
+ case R_MICROMIPS_PC10_S1:
+ case R_MICROMIPS_PC16_S1:
+ case R_MICROMIPS_PC23_S2:
if (h)
((struct mips_elf_link_hash_entry *) h)->has_static_relocs = TRUE;
break;
info->flags |= DF_TEXTREL;
}
}
- else if (r_type == R_MIPS_CALL_LO16
- || r_type == R_MIPS_GOT_LO16
- || r_type == R_MIPS_GOT_DISP
+ else if (call_lo16_reloc_p (r_type)
+ || got_lo16_reloc_p (r_type)
+ || got_disp_reloc_p (r_type)
|| (got16_reloc_p (r_type) && htab->is_vxworks))
{
/* We may need a local GOT entry for this relocation. We
return FALSE;
}
- if (h != NULL && mips_elf_relocation_needs_la25_stub (abfd, r_type))
+ if (h != NULL
+ && mips_elf_relocation_needs_la25_stub (abfd, r_type,
+ ELF_ST_IS_MIPS16 (h->other)))
((struct mips_elf_link_hash_entry *) h)->has_nonpic_branches = TRUE;
switch (r_type)
{
case R_MIPS_CALL16:
case R_MIPS16_CALL16:
+ case R_MICROMIPS_CALL16:
if (h == NULL)
{
(*_bfd_error_handler)
case R_MIPS_CALL_HI16:
case R_MIPS_CALL_LO16:
+ case R_MICROMIPS_CALL_HI16:
+ case R_MICROMIPS_CALL_LO16:
if (h != NULL)
{
- /* VxWorks call relocations point at the function's .got.plt
- entry, which will be allocated by adjust_dynamic_symbol.
- Otherwise, this symbol requires a global GOT entry. */
- if ((!htab->is_vxworks || h->forced_local)
- && !mips_elf_record_global_got_symbol (h, abfd, info, 0))
+ /* Make sure there is room in the regular GOT to hold the
+ function's address. We may eliminate it in favour of
+ a .got.plt entry later; see mips_elf_count_got_symbols. */
+ if (!mips_elf_record_global_got_symbol (h, abfd, info, TRUE, 0))
return FALSE;
/* We need a stub, not a plt entry for the undefined
break;
case R_MIPS_GOT_PAGE:
+ case R_MICROMIPS_GOT_PAGE:
/* If this is a global, overridable symbol, GOT_PAGE will
decay to GOT_DISP, so we'll need a GOT entry for it. */
if (h)
case R_MIPS_GOT16:
case R_MIPS_GOT_HI16:
case R_MIPS_GOT_LO16:
- if (!h || r_type == R_MIPS_GOT_PAGE)
+ case R_MICROMIPS_GOT16:
+ case R_MICROMIPS_GOT_HI16:
+ case R_MICROMIPS_GOT_LO16:
+ if (!h || got_page_reloc_p (r_type))
{
/* This relocation needs (or may need, if h != NULL) a
page entry in the GOT. For R_MIPS_GOT_PAGE we do not
howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, r_type, FALSE);
addend = mips_elf_read_rel_addend (abfd, rel,
howto, contents);
- if (r_type == R_MIPS_GOT16)
+ if (got16_reloc_p (r_type))
mips_elf_add_lo16_rel_addend (abfd, rel, rel_end,
contents, &addend);
else
if (!mips_elf_record_got_page_entry (info, abfd, r_symndx,
addend))
return FALSE;
- break;
}
/* Fall through. */
case R_MIPS_GOT_DISP:
- if (h && !mips_elf_record_global_got_symbol (h, abfd, info, 0))
+ case R_MICROMIPS_GOT_DISP:
+ if (h && !mips_elf_record_global_got_symbol (h, abfd, info,
+ FALSE, 0))
return FALSE;
break;
case R_MIPS_TLS_GOTTPREL:
+ case R_MIPS16_TLS_GOTTPREL:
+ case R_MICROMIPS_TLS_GOTTPREL:
if (info->shared)
info->flags |= DF_STATIC_TLS;
/* Fall through */
case R_MIPS_TLS_LDM:
- if (r_type == R_MIPS_TLS_LDM)
+ case R_MIPS16_TLS_LDM:
+ case R_MICROMIPS_TLS_LDM:
+ if (tls_ldm_reloc_p (r_type))
{
- r_symndx = 0;
+ r_symndx = STN_UNDEF;
h = NULL;
}
/* Fall through */
case R_MIPS_TLS_GD:
+ case R_MIPS16_TLS_GD:
+ case R_MICROMIPS_TLS_GD:
/* This symbol requires a global offset table entry, or two
for TLS GD relocations. */
{
- unsigned char flag = (r_type == R_MIPS_TLS_GD
- ? GOT_TLS_GD
- : r_type == R_MIPS_TLS_LDM
- ? GOT_TLS_LDM
- : GOT_TLS_IE);
+ unsigned char flag;
+
+ flag = (tls_gd_reloc_p (r_type)
+ ? GOT_TLS_GD
+ : tls_ldm_reloc_p (r_type) ? GOT_TLS_LDM : GOT_TLS_IE);
if (h != NULL)
{
struct mips_elf_link_hash_entry *hmips =
(struct mips_elf_link_hash_entry *) h;
hmips->tls_type |= flag;
- if (h && !mips_elf_record_global_got_symbol (h, abfd,
- info, flag))
+ if (h && !mips_elf_record_global_got_symbol (h, abfd, info,
+ FALSE, flag))
return FALSE;
}
else
{
- BFD_ASSERT (flag == GOT_TLS_LDM || r_symndx != 0);
+ BFD_ASSERT (flag == GOT_TLS_LDM || r_symndx != STN_UNDEF);
if (!mips_elf_record_local_got_symbol (abfd, r_symndx,
rel->r_addend,
case R_MIPS_GPREL16:
case R_MIPS_LITERAL:
case R_MIPS_GPREL32:
+ case R_MICROMIPS_26_S1:
+ case R_MICROMIPS_GPREL16:
+ case R_MICROMIPS_LITERAL:
+ case R_MICROMIPS_GPREL7_S2:
if (SGI_COMPAT (abfd))
mips_elf_hash_table (info)->compact_rel_size +=
sizeof (Elf32_External_crinfo);
case R_MIPS_CALL_HI16:
case R_MIPS_CALL_LO16:
case R_MIPS_JALR:
+ case R_MICROMIPS_CALL16:
+ case R_MICROMIPS_CALL_HI16:
+ case R_MICROMIPS_CALL_LO16:
+ case R_MICROMIPS_JALR:
break;
}
case R_MIPS_HI16:
case R_MIPS_HIGHER:
case R_MIPS_HIGHEST:
+ case R_MICROMIPS_HI16:
+ case R_MICROMIPS_HIGHER:
+ case R_MICROMIPS_HIGHEST:
/* Don't refuse a high part relocation if it's against
no symbol (e.g. part of a compound relocation). */
- if (r_symndx == 0)
+ if (r_symndx == STN_UNDEF)
break;
/* R_MIPS_HI16 against _gp_disp is used for $gp setup,
&& strcmp (h->root.root.string, "_gp_disp") == 0)
break;
+ /* Likewise __GOTT_BASE__ and __GOTT_INDEX__ on VxWorks. */
+ if (is_gott_symbol (info, h))
+ break;
+
/* FALLTHROUGH */
case R_MIPS16_26:
case R_MIPS_26:
+ case R_MICROMIPS_26_S1:
howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, r_type, FALSE);
(*_bfd_error_handler)
(_("%B: relocation %s against `%s' can not be used when making a shared object; recompile with -fPIC"),
struct mips_elf_link_hash_table *htab;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
dynobj = elf_hash_table (info)->dynobj;
hmips = (struct mips_elf_link_hash_entry *) h;
if (htab->is_vxworks && !info->shared)
return TRUE;
- /* Ignore indirect and warning symbols. All relocations against
- such symbols will be redirected to the target symbol. */
- if (h->root.type == bfd_link_hash_indirect
- || h->root.type == bfd_link_hash_warning)
+ /* Ignore indirect symbols. All relocations against such symbols
+ will be redirected to the target symbol. */
+ if (h->root.type == bfd_link_hash_indirect)
return TRUE;
/* If this symbol is defined in a dynamic object, or we are creating
if (do_copy)
{
/* Even though we don't directly need a GOT entry for this symbol,
- a symbol must have a dynamic symbol table index greater that
- DT_MIPS_GOTSYM if there are dynamic relocations against it. */
- if (hmips->global_got_area > GGA_RELOC_ONLY)
- hmips->global_got_area = GGA_RELOC_ONLY;
+ the SVR4 psABI requires it to have a dynamic symbol table
+ index greater that DT_MIPS_GOTSYM if there are dynamic
+ relocations against it.
+
+ VxWorks does not enforce the same mapping between the GOT
+ and the symbol table, so the same requirement does not
+ apply there. */
+ if (!htab->is_vxworks)
+ {
+ if (hmips->global_got_area > GGA_RELOC_ONLY)
+ hmips->global_got_area = GGA_RELOC_ONLY;
+ hmips->got_only_for_calls = FALSE;
+ }
mips_elf_allocate_dynamic_relocations
(dynobj, info, hmips->possibly_dynamic_relocs);
struct mips_elf_link_hash_table *htab;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
dynobj = elf_hash_table (info)->dynobj;
hmips = (struct mips_elf_link_hash_entry *) h;
/* On non-VxWorks targets, the first two entries in .got.plt
are reserved. */
if (!htab->is_vxworks)
- htab->sgotplt->size += 2 * MIPS_ELF_GOT_SIZE (dynobj);
+ htab->sgotplt->size
+ += get_elf_backend_data (dynobj)->got_header_size;
/* On VxWorks, also allocate room for the header's
.rela.plt.unloaded entries. */
struct mips_htab_traverse_info hti;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
/* The .reginfo section has a fixed size. */
ri = bfd_get_section_by_name (output_bfd, ".reginfo");
struct mips_elf_link_hash_table *htab;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
s = htab->sgot;
if (s == NULL)
return TRUE;
return FALSE;
/* Count the number of GOT symbols. */
- mips_elf_link_hash_traverse (htab, mips_elf_count_got_symbols, g);
+ mips_elf_link_hash_traverse (htab, mips_elf_count_got_symbols, info);
/* Calculate the total loadable size of the output. That
will give us the maximum number of GOT_PAGE entries
bfd_size_type dynsymcount;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
if (htab->lazy_stub_count == 0)
return;
struct mips_elf_link_hash_table *htab;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
if (htab->lazy_stub_count == 0)
return;
htab->sstubs->size = 0;
- mips_elf_link_hash_traverse (mips_elf_hash_table (info),
- mips_elf_allocate_lazy_stub, htab);
+ mips_elf_link_hash_traverse (htab, mips_elf_allocate_lazy_stub, htab);
htab->sstubs->size += htab->function_stub_size;
BFD_ASSERT (htab->sstubs->size
== htab->lazy_stub_count * htab->function_stub_size);
struct mips_elf_link_hash_table *htab;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
dynobj = elf_hash_table (info)->dynobj;
BFD_ASSERT (dynobj != NULL);
/* Set the contents of the .interp section to the interpreter. */
if (info->executable)
{
- s = bfd_get_section_by_name (dynobj, ".interp");
+ s = bfd_get_linker_section (dynobj, ".interp");
BFD_ASSERT (s != NULL);
s->size
= strlen (ELF_DYNAMIC_INTERPRETER (output_bfd)) + 1;
}
/* Allocate space for global sym dynamic relocs. */
- elf_link_hash_traverse (&htab->root, allocate_dynrelocs, (PTR) info);
+ elf_link_hash_traverse (&htab->root, allocate_dynrelocs, info);
mips_elf_estimate_stub_size (output_bfd, info);
{
/* We add a room for __rld_map. It will be filled in by the
rtld to contain a pointer to the _r_debug structure. */
- s->size += 4;
+ s->size += MIPS_ELF_RLD_MAP_SIZE (output_bfd);
}
else if (SGI_COMPAT (output_bfd)
&& CONST_STRNEQ (name, ".compact_rel"))
/* SGI object has the equivalence of DT_DEBUG in the
DT_MIPS_RLD_MAP entry. This must come first because glibc
- only fills in DT_MIPS_RLD_MAP (not DT_DEBUG) and GDB only
- looks at the first one it sees. */
+ only fills in DT_MIPS_RLD_MAP (not DT_DEBUG) and some tools
+ may only look at the first one they see. */
if (!info->shared
&& !MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_RLD_MAP, 0))
return FALSE;
if (IRIX_COMPAT (dynobj) == ict_irix6
&& (bfd_get_section_by_name
- (dynobj, MIPS_ELF_OPTIONS_SECTION_NAME (dynobj)))
+ (output_bfd, MIPS_ELF_OPTIONS_SECTION_NAME (dynobj)))
&& !MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_OPTIONS, 0))
return FALSE;
}
Elf_Internal_Sym *sym;
asection *sec;
- if (mips_elf_local_relocation_p (input_bfd, rel, local_sections, FALSE))
+ if (mips_elf_local_relocation_p (input_bfd, rel, local_sections))
{
r_type = ELF_R_TYPE (output_bfd, rel->r_info);
- if (r_type == R_MIPS16_GPREL
- || r_type == R_MIPS_GPREL16
+ if (gprel16_reloc_p (r_type)
|| r_type == R_MIPS_GPREL32
- || r_type == R_MIPS_LITERAL)
+ || literal_reloc_p (r_type))
{
rel->r_addend += _bfd_get_gp_value (input_bfd);
rel->r_addend -= _bfd_get_gp_value (output_bfd);
}
}
-/* Relocate a MIPS ELF section. */
+/* Handle relocations against symbols from removed linkonce sections,
+ or sections discarded by a linker script. We use this wrapper around
+ RELOC_AGAINST_DISCARDED_SECTION to handle triplets of compound relocs
+ on 64-bit ELF targets. In this case for any relocation handled, which
+ always be the first in a triplet, the remaining two have to be processed
+ together with the first, even if they are R_MIPS_NONE. It is the symbol
+ index referred by the first reloc that applies to all the three and the
+ remaining two never refer to an object symbol. And it is the final
+ relocation (the last non-null one) that determines the output field of
+ the whole relocation so retrieve the corresponding howto structure for
+ the relocatable field to be cleared by RELOC_AGAINST_DISCARDED_SECTION.
+
+ Note that RELOC_AGAINST_DISCARDED_SECTION is a macro that uses "continue"
+ and therefore requires to be pasted in a loop. It also defines a block
+ and does not protect any of its arguments, hence the extra brackets. */
+
+static void
+mips_reloc_against_discarded_section (bfd *output_bfd,
+ struct bfd_link_info *info,
+ bfd *input_bfd, asection *input_section,
+ Elf_Internal_Rela **rel,
+ const Elf_Internal_Rela **relend,
+ bfd_boolean rel_reloc,
+ reloc_howto_type *howto,
+ bfd_byte *contents)
+{
+ const struct elf_backend_data *bed = get_elf_backend_data (output_bfd);
+ int count = bed->s->int_rels_per_ext_rel;
+ unsigned int r_type;
+ int i;
+
+ for (i = count - 1; i > 0; i--)
+ {
+ r_type = ELF_R_TYPE (output_bfd, (*rel)[i].r_info);
+ if (r_type != R_MIPS_NONE)
+ {
+ howto = MIPS_ELF_RTYPE_TO_HOWTO (input_bfd, r_type, !rel_reloc);
+ break;
+ }
+ }
+ do
+ {
+ RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
+ (*rel), count, (*relend),
+ howto, i, contents);
+ }
+ while (0);
+}
+
+/* Relocate a MIPS ELF section. */
bfd_boolean
_bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
const char *name;
bfd_vma value = 0;
reloc_howto_type *howto;
- bfd_boolean require_jalx;
+ bfd_boolean cross_mode_jump_p;
/* TRUE if the relocation is a RELA relocation, rather than a
REL relocation. */
bfd_boolean rela_relocation_p = TRUE;
asection *sec;
Elf_Internal_Shdr *symtab_hdr;
struct elf_link_hash_entry *h;
+ bfd_boolean rel_reloc;
+ rel_reloc = (NEWABI_P (input_bfd)
+ && mips_elf_rel_relocation_p (input_bfd, input_section,
+ relocs, rel));
/* Find the relocation howto for this relocation. */
- howto = MIPS_ELF_RTYPE_TO_HOWTO (input_bfd, r_type,
- NEWABI_P (input_bfd)
- && (MIPS_RELOC_RELA_P
- (input_bfd, input_section,
- rel - relocs)));
+ howto = MIPS_ELF_RTYPE_TO_HOWTO (input_bfd, r_type, !rel_reloc);
r_symndx = ELF_R_SYM (input_bfd, rel->r_info);
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
- if (mips_elf_local_relocation_p (input_bfd, rel, local_sections, FALSE))
+ if (mips_elf_local_relocation_p (input_bfd, rel, local_sections))
{
sec = local_sections[r_symndx];
h = NULL;
sec = h->root.u.def.section;
}
- if (sec != NULL && elf_discarded_section (sec))
+ if (sec != NULL && discarded_section (sec))
{
- /* For relocs against symbols from removed linkonce sections,
- or sections discarded by a linker script, we just want the
- section contents zeroed. Avoid any special processing. */
- _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
- rel->r_info = 0;
- rel->r_addend = 0;
+ mips_reloc_against_discarded_section (output_bfd, info, input_bfd,
+ input_section, &rel, &relend,
+ rel_reloc, howto, contents);
continue;
}
if (hi16_reloc_p (r_type)
|| (got16_reloc_p (r_type)
&& mips_elf_local_relocation_p (input_bfd, rel,
- local_sections, FALSE)))
+ local_sections)))
{
if (!mips_elf_add_lo16_rel_addend (input_bfd, rel, relend,
contents, &addend))
input_section, info, rel,
addend, howto, local_syms,
local_sections, &value,
- &name, &require_jalx,
+ &name, &cross_mode_jump_p,
use_saved_addend_p))
{
case bfd_reloc_continue:
struct mips_elf_link_hash_table *htab;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
BFD_ASSERT (name != NULL);
if (!htab->small_data_overflow_reported
- && (howto->type == R_MIPS_GPREL16
- || howto->type == R_MIPS_LITERAL))
+ && (gprel16_reloc_p (howto->type)
+ || literal_reloc_p (howto->type)))
{
msg = _("small-data section exceeds 64KB;"
" lower small-data size limit (see option -G)");
case bfd_reloc_ok:
break;
+ case bfd_reloc_outofrange:
+ if (jal_reloc_p (howto->type))
+ {
+ msg = _("JALX to a non-word-aligned address");
+ info->callbacks->warning
+ (info, msg, name, input_bfd, input_section, rel->r_offset);
+ return FALSE;
+ }
+ /* Fall through. */
+
default:
abort ();
break;
/* Actually perform the relocation. */
if (! mips_elf_perform_relocation (info, howto, rel, value,
input_bfd, input_section,
- contents, require_jalx))
+ contents, cross_mode_jump_p))
return FALSE;
}
stub = (struct mips_elf_la25_stub *) *slot;
hti = (struct mips_htab_traverse_info *) data;
htab = mips_elf_hash_table (hti->info);
+ BFD_ASSERT (htab != NULL);
/* Create the section contents, if we haven't already. */
s = stub->stub_section;
offset = stub->offset;
/* Work out the target address. */
- target = (stub->h->root.root.u.def.section->output_section->vma
- + stub->h->root.root.u.def.section->output_offset
- + stub->h->root.root.u.def.value);
+ target = mips_elf_get_la25_target (stub, &s);
+ target += s->output_section->vma + s->output_offset;
+
target_high = ((target + 0x8000) >> 16) & 0xffff;
target_low = (target & 0xffff);
if (stub->stub_section != htab->strampoline)
{
- /* This is a simple LUI/ADIDU stub. Zero out the beginning
+ /* This is a simple LUI/ADDIU stub. Zero out the beginning
of the section and write the two instructions at the end. */
memset (loc, 0, offset);
loc += offset;
- bfd_put_32 (hti->output_bfd, LA25_LUI (target_high), loc);
- bfd_put_32 (hti->output_bfd, LA25_ADDIU (target_low), loc + 4);
+ if (ELF_ST_IS_MICROMIPS (stub->h->root.other))
+ {
+ bfd_put_micromips_32 (hti->output_bfd,
+ LA25_LUI_MICROMIPS (target_high),
+ loc);
+ bfd_put_micromips_32 (hti->output_bfd,
+ LA25_ADDIU_MICROMIPS (target_low),
+ loc + 4);
+ }
+ else
+ {
+ bfd_put_32 (hti->output_bfd, LA25_LUI (target_high), loc);
+ bfd_put_32 (hti->output_bfd, LA25_ADDIU (target_low), loc + 4);
+ }
}
else
{
/* This is trampoline. */
loc += offset;
- bfd_put_32 (hti->output_bfd, LA25_LUI (target_high), loc);
- bfd_put_32 (hti->output_bfd, LA25_J (target), loc + 4);
- bfd_put_32 (hti->output_bfd, LA25_ADDIU (target_low), loc + 8);
- bfd_put_32 (hti->output_bfd, 0, loc + 12);
+ if (ELF_ST_IS_MICROMIPS (stub->h->root.other))
+ {
+ bfd_put_micromips_32 (hti->output_bfd,
+ LA25_LUI_MICROMIPS (target_high), loc);
+ bfd_put_micromips_32 (hti->output_bfd,
+ LA25_J_MICROMIPS (target), loc + 4);
+ bfd_put_micromips_32 (hti->output_bfd,
+ LA25_ADDIU_MICROMIPS (target_low), loc + 8);
+ bfd_put_32 (hti->output_bfd, 0, loc + 12);
+ }
+ else
+ {
+ bfd_put_32 (hti->output_bfd, LA25_LUI (target_high), loc);
+ bfd_put_32 (hti->output_bfd, LA25_J (target), loc + 4);
+ bfd_put_32 (hti->output_bfd, LA25_ADDIU (target_low), loc + 8);
+ bfd_put_32 (hti->output_bfd, 0, loc + 12);
+ }
}
return TRUE;
}
struct mips_elf_link_hash_entry *hmips;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
dynobj = elf_hash_table (info)->dynobj;
hmips = (struct mips_elf_link_hash_entry *) h;
/* Run through the global symbol table, creating GOT entries for all
the symbols that need them. */
- if (g->global_gotsym != NULL
- && h->dynindx >= g->global_gotsym->dynindx)
+ if (hmips->global_got_area != GGA_NONE)
{
bfd_vma offset;
bfd_vma value;
MIPS_ELF_PUT_WORD (output_bfd, value, sgot->contents + offset);
}
- if (g->next && h->dynindx != -1 && h->type != STT_TLS)
+ if (hmips->global_got_area != GGA_NONE && g->next && h->type != STT_TLS)
{
struct mips_got_entry e, *p;
bfd_vma entry;
/* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */
name = h->root.root.string;
- if (strcmp (name, "_DYNAMIC") == 0
+ if (h == elf_hash_table (info)->hdynamic
|| h == elf_hash_table (info)->hgot)
sym->st_shndx = SHN_ABS;
else if (strcmp (name, "_DYNAMIC_LINK") == 0
if (IRIX_COMPAT (output_bfd) == ict_irix6)
mips_elf_irix6_finish_dynamic_symbol (output_bfd, name, sym);
- if (! info->shared)
- {
- if (! mips_elf_hash_table (info)->use_rld_obj_head
- && (strcmp (name, "__rld_map") == 0
- || strcmp (name, "__RLD_MAP") == 0))
- {
- asection *s = bfd_get_section_by_name (dynobj, ".rld_map");
- BFD_ASSERT (s != NULL);
- sym->st_value = s->output_section->vma + s->output_offset;
- bfd_put_32 (output_bfd, 0, s->contents);
- if (mips_elf_hash_table (info)->rld_value == 0)
- mips_elf_hash_table (info)->rld_value = sym->st_value;
- }
- else if (mips_elf_hash_table (info)->use_rld_obj_head
- && strcmp (name, "__rld_obj_head") == 0)
- {
- /* IRIX6 does not use a .rld_map section. */
- if (IRIX_COMPAT (output_bfd) == ict_irix5
- || IRIX_COMPAT (output_bfd) == ict_none)
- BFD_ASSERT (bfd_get_section_by_name (dynobj, ".rld_map")
- != NULL);
- mips_elf_hash_table (info)->rld_value = sym->st_value;
- }
- }
-
/* Keep dynamic MIPS16 symbols odd. This allows the dynamic linker to
treat MIPS16 symbols like any other. */
if (ELF_ST_IS_MIPS16 (sym->st_other))
asection *sgot;
struct mips_got_info *g;
struct mips_elf_link_hash_table *htab;
+ struct mips_elf_link_hash_entry *hmips;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
dynobj = elf_hash_table (info)->dynobj;
+ hmips = (struct mips_elf_link_hash_entry *) h;
if (h->plt.offset != (bfd_vma) -1)
{
BFD_ASSERT (g != NULL);
/* See if this symbol has an entry in the GOT. */
- if (g->global_gotsym != NULL
- && h->dynindx >= g->global_gotsym->dynindx)
+ if (hmips->global_got_area != GGA_NONE)
{
bfd_vma offset;
Elf_Internal_Rela outrel;
++htab->srelbss->reloc_count;
}
- /* If this is a mips16 symbol, force the value to be even. */
- if (ELF_ST_IS_MIPS16 (sym->st_other))
+ /* If this is a mips16/microMIPS symbol, force the value to be even. */
+ if (ELF_ST_IS_COMPRESSED (sym->st_other))
sym->st_value &= ~1;
return TRUE;
struct mips_elf_link_hash_table *htab;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
if (ABI_64_P (output_bfd))
plt_entry = mips_n64_exec_plt0_entry;
else if (ABI_N32_P (output_bfd))
struct mips_elf_link_hash_table *htab;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
plt_entry = mips_vxworks_exec_plt0_entry;
/* Calculate the value of _GLOBAL_OFFSET_TABLE_. */
struct mips_elf_link_hash_table *htab;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
/* We just need to copy the entry byte-by-byte. */
for (i = 0; i < ARRAY_SIZE (mips_vxworks_shared_plt0_entry); i++)
struct mips_elf_link_hash_table *htab;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
dynobj = elf_hash_table (info)->dynobj;
- sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
+ sdyn = bfd_get_linker_section (dynobj, ".dynamic");
sgot = htab->sgot;
gg = htab->got_info;
break;
case DT_MIPS_RLD_MAP:
- dyn.d_un.d_ptr = mips_elf_hash_table (info)->rld_value;
+ {
+ struct elf_link_hash_entry *h;
+ h = mips_elf_hash_table (info)->rld_symbol;
+ if (!h)
+ {
+ dyn_to_skip = MIPS_ELF_DYN_SIZE (dynobj);
+ swap_out_p = FALSE;
+ break;
+ }
+ s = h->root.u.def.section;
+ dyn.d_un.d_ptr = (s->output_section->vma + s->output_offset
+ + h->root.u.def.value);
+ }
break;
case DT_MIPS_OPTIONS:
if (SGI_COMPAT (output_bfd))
{
/* Write .compact_rel section out. */
- s = bfd_get_section_by_name (dynobj, ".compact_rel");
+ s = bfd_get_linker_section (dynobj, ".compact_rel");
if (s != NULL)
{
cpt.id1 = 1;
val = E_MIPS_ARCH_64 | E_MIPS_MACH_SB1;
break;
+ case bfd_mach_mips_loongson_3a:
+ val = E_MIPS_ARCH_64 | E_MIPS_MACH_LS3A;
+ break;
+
case bfd_mach_mips_octeon:
+ case bfd_mach_mips_octeonp:
val = E_MIPS_ARCH_64R2 | E_MIPS_MACH_OCTEON;
break;
val = E_MIPS_ARCH_64 | E_MIPS_MACH_XLR;
break;
+ case bfd_mach_mips_octeon2:
+ val = E_MIPS_ARCH_64R2 | E_MIPS_MACH_OCTEON2;
+ break;
+
case bfd_mach_mipsisa32:
val = E_MIPS_ARCH_32;
break;
case R_MIPS_GOT_DISP:
case R_MIPS_GOT_PAGE:
case R_MIPS_GOT_OFST:
+ case R_MICROMIPS_GOT16:
+ case R_MICROMIPS_CALL16:
+ case R_MICROMIPS_CALL_HI16:
+ case R_MICROMIPS_CALL_LO16:
+ case R_MICROMIPS_GOT_HI16:
+ case R_MICROMIPS_GOT_LO16:
+ case R_MICROMIPS_GOT_DISP:
+ case R_MICROMIPS_GOT_PAGE:
+ case R_MICROMIPS_GOT_OFST:
/* ??? It would seem that the existing MIPS code does no sort
of reference counting or whatnot on its GOT and PLT entries,
so it is not possible to garbage collect them at this time. */
return TRUE;
}
\f
+/* microMIPS code retains local labels for linker relaxation. Omit them
+ from output by default for clarity. */
+
+bfd_boolean
+_bfd_mips_elf_is_target_special_symbol (bfd *abfd, asymbol *sym)
+{
+ return _bfd_elf_is_local_label_name (abfd, sym->name);
+}
+
/* MIPS ELF uses a special find_nearest_line routine in order the
handle the ECOFF debugging information. */
line_ptr))
return TRUE;
- if (_bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset,
+ if (_bfd_dwarf2_find_nearest_line (abfd, dwarf_debug_sections,
+ section, symbols, offset,
filename_ptr, functionname_ptr,
- line_ptr, ABI_64_P (abfd) ? 8 : 0,
+ line_ptr, NULL, ABI_64_P (abfd) ? 8 : 0,
&elf_tdata (abfd)->dwarf2_find_line_info))
return TRUE;
return NULL;
}
\f
-/* Allocate ABFD's target-dependent data. */
+static bfd_boolean
+mips_elf_relax_delete_bytes (bfd *abfd,
+ asection *sec, bfd_vma addr, int count)
+{
+ Elf_Internal_Shdr *symtab_hdr;
+ unsigned int sec_shndx;
+ bfd_byte *contents;
+ Elf_Internal_Rela *irel, *irelend;
+ Elf_Internal_Sym *isym;
+ Elf_Internal_Sym *isymend;
+ struct elf_link_hash_entry **sym_hashes;
+ struct elf_link_hash_entry **end_hashes;
+ struct elf_link_hash_entry **start_hashes;
+ unsigned int symcount;
-bfd_boolean
-_bfd_mips_elf_mkobject (bfd *abfd)
+ sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
+ contents = elf_section_data (sec)->this_hdr.contents;
+
+ irel = elf_section_data (sec)->relocs;
+ irelend = irel + sec->reloc_count;
+
+ /* Actually delete the bytes. */
+ memmove (contents + addr, contents + addr + count,
+ (size_t) (sec->size - addr - count));
+ sec->size -= count;
+
+ /* Adjust all the relocs. */
+ for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++)
+ {
+ /* Get the new reloc address. */
+ if (irel->r_offset > addr)
+ irel->r_offset -= count;
+ }
+
+ BFD_ASSERT (addr % 2 == 0);
+ BFD_ASSERT (count % 2 == 0);
+
+ /* Adjust the local symbols defined in this section. */
+ symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ isym = (Elf_Internal_Sym *) symtab_hdr->contents;
+ for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++)
+ if (isym->st_shndx == sec_shndx && isym->st_value > addr)
+ isym->st_value -= count;
+
+ /* Now adjust the global symbols defined in this section. */
+ symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
+ - symtab_hdr->sh_info);
+ sym_hashes = start_hashes = elf_sym_hashes (abfd);
+ end_hashes = sym_hashes + symcount;
+
+ for (; sym_hashes < end_hashes; sym_hashes++)
+ {
+ struct elf_link_hash_entry *sym_hash = *sym_hashes;
+
+ if ((sym_hash->root.type == bfd_link_hash_defined
+ || sym_hash->root.type == bfd_link_hash_defweak)
+ && sym_hash->root.u.def.section == sec)
+ {
+ bfd_vma value = sym_hash->root.u.def.value;
+
+ if (ELF_ST_IS_MICROMIPS (sym_hash->other))
+ value &= MINUS_TWO;
+ if (value > addr)
+ sym_hash->root.u.def.value -= count;
+ }
+ }
+
+ return TRUE;
+}
+
+
+/* Opcodes needed for microMIPS relaxation as found in
+ opcodes/micromips-opc.c. */
+
+struct opcode_descriptor {
+ unsigned long match;
+ unsigned long mask;
+};
+
+/* The $ra register aka $31. */
+
+#define RA 31
+
+/* 32-bit instruction format register fields. */
+
+#define OP32_SREG(opcode) (((opcode) >> 16) & 0x1f)
+#define OP32_TREG(opcode) (((opcode) >> 21) & 0x1f)
+
+/* Check if a 5-bit register index can be abbreviated to 3 bits. */
+
+#define OP16_VALID_REG(r) \
+ ((2 <= (r) && (r) <= 7) || (16 <= (r) && (r) <= 17))
+
+
+/* 32-bit and 16-bit branches. */
+
+static const struct opcode_descriptor b_insns_32[] = {
+ { /* "b", "p", */ 0x40400000, 0xffff0000 }, /* bgez 0 */
+ { /* "b", "p", */ 0x94000000, 0xffff0000 }, /* beq 0, 0 */
+ { 0, 0 } /* End marker for find_match(). */
+};
+
+static const struct opcode_descriptor bc_insn_32 =
+ { /* "bc(1|2)(ft)", "N,p", */ 0x42800000, 0xfec30000 };
+
+static const struct opcode_descriptor bz_insn_32 =
+ { /* "b(g|l)(e|t)z", "s,p", */ 0x40000000, 0xff200000 };
+
+static const struct opcode_descriptor bzal_insn_32 =
+ { /* "b(ge|lt)zal", "s,p", */ 0x40200000, 0xffa00000 };
+
+static const struct opcode_descriptor beq_insn_32 =
+ { /* "b(eq|ne)", "s,t,p", */ 0x94000000, 0xdc000000 };
+
+static const struct opcode_descriptor b_insn_16 =
+ { /* "b", "mD", */ 0xcc00, 0xfc00 };
+
+static const struct opcode_descriptor bz_insn_16 =
+ { /* "b(eq|ne)z", "md,mE", */ 0x8c00, 0xdc00 };
+
+
+/* 32-bit and 16-bit branch EQ and NE zero. */
+
+/* NOTE: All opcode tables have BEQ/BNE in the same order: first the
+ eq and second the ne. This convention is used when replacing a
+ 32-bit BEQ/BNE with the 16-bit version. */
+
+#define BZC32_REG_FIELD(r) (((r) & 0x1f) << 16)
+
+static const struct opcode_descriptor bz_rs_insns_32[] = {
+ { /* "beqz", "s,p", */ 0x94000000, 0xffe00000 },
+ { /* "bnez", "s,p", */ 0xb4000000, 0xffe00000 },
+ { 0, 0 } /* End marker for find_match(). */
+};
+
+static const struct opcode_descriptor bz_rt_insns_32[] = {
+ { /* "beqz", "t,p", */ 0x94000000, 0xfc01f000 },
+ { /* "bnez", "t,p", */ 0xb4000000, 0xfc01f000 },
+ { 0, 0 } /* End marker for find_match(). */
+};
+
+static const struct opcode_descriptor bzc_insns_32[] = {
+ { /* "beqzc", "s,p", */ 0x40e00000, 0xffe00000 },
+ { /* "bnezc", "s,p", */ 0x40a00000, 0xffe00000 },
+ { 0, 0 } /* End marker for find_match(). */
+};
+
+static const struct opcode_descriptor bz_insns_16[] = {
+ { /* "beqz", "md,mE", */ 0x8c00, 0xfc00 },
+ { /* "bnez", "md,mE", */ 0xac00, 0xfc00 },
+ { 0, 0 } /* End marker for find_match(). */
+};
+
+/* Switch between a 5-bit register index and its 3-bit shorthand. */
+
+#define BZ16_REG(opcode) ((((((opcode) >> 7) & 7) + 0x1e) & 0x17) + 2)
+#define BZ16_REG_FIELD(r) \
+ (((2 <= (r) && (r) <= 7) ? (r) : ((r) - 16)) << 7)
+
+
+/* 32-bit instructions with a delay slot. */
+
+static const struct opcode_descriptor jal_insn_32_bd16 =
+ { /* "jals", "a", */ 0x74000000, 0xfc000000 };
+
+static const struct opcode_descriptor jal_insn_32_bd32 =
+ { /* "jal", "a", */ 0xf4000000, 0xfc000000 };
+
+static const struct opcode_descriptor jal_x_insn_32_bd32 =
+ { /* "jal[x]", "a", */ 0xf0000000, 0xf8000000 };
+
+static const struct opcode_descriptor j_insn_32 =
+ { /* "j", "a", */ 0xd4000000, 0xfc000000 };
+
+static const struct opcode_descriptor jalr_insn_32 =
+ { /* "jalr[.hb]", "t,s", */ 0x00000f3c, 0xfc00efff };
+
+/* This table can be compacted, because no opcode replacement is made. */
+
+static const struct opcode_descriptor ds_insns_32_bd16[] = {
+ { /* "jals", "a", */ 0x74000000, 0xfc000000 },
+
+ { /* "jalrs[.hb]", "t,s", */ 0x00004f3c, 0xfc00efff },
+ { /* "b(ge|lt)zals", "s,p", */ 0x42200000, 0xffa00000 },
+
+ { /* "b(g|l)(e|t)z", "s,p", */ 0x40000000, 0xff200000 },
+ { /* "b(eq|ne)", "s,t,p", */ 0x94000000, 0xdc000000 },
+ { /* "j", "a", */ 0xd4000000, 0xfc000000 },
+ { 0, 0 } /* End marker for find_match(). */
+};
+
+/* This table can be compacted, because no opcode replacement is made. */
+
+static const struct opcode_descriptor ds_insns_32_bd32[] = {
+ { /* "jal[x]", "a", */ 0xf0000000, 0xf8000000 },
+
+ { /* "jalr[.hb]", "t,s", */ 0x00000f3c, 0xfc00efff },
+ { /* "b(ge|lt)zal", "s,p", */ 0x40200000, 0xffa00000 },
+ { 0, 0 } /* End marker for find_match(). */
+};
+
+
+/* 16-bit instructions with a delay slot. */
+
+static const struct opcode_descriptor jalr_insn_16_bd16 =
+ { /* "jalrs", "my,mj", */ 0x45e0, 0xffe0 };
+
+static const struct opcode_descriptor jalr_insn_16_bd32 =
+ { /* "jalr", "my,mj", */ 0x45c0, 0xffe0 };
+
+static const struct opcode_descriptor jr_insn_16 =
+ { /* "jr", "mj", */ 0x4580, 0xffe0 };
+
+#define JR16_REG(opcode) ((opcode) & 0x1f)
+
+/* This table can be compacted, because no opcode replacement is made. */
+
+static const struct opcode_descriptor ds_insns_16_bd16[] = {
+ { /* "jalrs", "my,mj", */ 0x45e0, 0xffe0 },
+
+ { /* "b", "mD", */ 0xcc00, 0xfc00 },
+ { /* "b(eq|ne)z", "md,mE", */ 0x8c00, 0xdc00 },
+ { /* "jr", "mj", */ 0x4580, 0xffe0 },
+ { 0, 0 } /* End marker for find_match(). */
+};
+
+
+/* LUI instruction. */
+
+static const struct opcode_descriptor lui_insn =
+ { /* "lui", "s,u", */ 0x41a00000, 0xffe00000 };
+
+
+/* ADDIU instruction. */
+
+static const struct opcode_descriptor addiu_insn =
+ { /* "addiu", "t,r,j", */ 0x30000000, 0xfc000000 };
+
+static const struct opcode_descriptor addiupc_insn =
+ { /* "addiu", "mb,$pc,mQ", */ 0x78000000, 0xfc000000 };
+
+#define ADDIUPC_REG_FIELD(r) \
+ (((2 <= (r) && (r) <= 7) ? (r) : ((r) - 16)) << 23)
+
+
+/* Relaxable instructions in a JAL delay slot: MOVE. */
+
+/* The 16-bit move has rd in 9:5 and rs in 4:0. The 32-bit moves
+ (ADDU, OR) have rd in 15:11 and rs in 10:16. */
+#define MOVE32_RD(opcode) (((opcode) >> 11) & 0x1f)
+#define MOVE32_RS(opcode) (((opcode) >> 16) & 0x1f)
+
+#define MOVE16_RD_FIELD(r) (((r) & 0x1f) << 5)
+#define MOVE16_RS_FIELD(r) (((r) & 0x1f) )
+
+static const struct opcode_descriptor move_insns_32[] = {
+ { /* "move", "d,s", */ 0x00000150, 0xffe007ff }, /* addu d,s,$0 */
+ { /* "move", "d,s", */ 0x00000290, 0xffe007ff }, /* or d,s,$0 */
+ { 0, 0 } /* End marker for find_match(). */
+};
+
+static const struct opcode_descriptor move_insn_16 =
+ { /* "move", "mp,mj", */ 0x0c00, 0xfc00 };
+
+
+/* NOP instructions. */
+
+static const struct opcode_descriptor nop_insn_32 =
+ { /* "nop", "", */ 0x00000000, 0xffffffff };
+
+static const struct opcode_descriptor nop_insn_16 =
+ { /* "nop", "", */ 0x0c00, 0xffff };
+
+
+/* Instruction match support. */
+
+#define MATCH(opcode, insn) ((opcode & insn.mask) == insn.match)
+
+static int
+find_match (unsigned long opcode, const struct opcode_descriptor insn[])
{
- return bfd_elf_allocate_object (abfd, sizeof (struct elf_obj_tdata),
- MIPS_ELF_TDATA);
+ unsigned long indx;
+
+ for (indx = 0; insn[indx].mask != 0; indx++)
+ if (MATCH (opcode, insn[indx]))
+ return indx;
+
+ return -1;
+}
+
+
+/* Branch and delay slot decoding support. */
+
+/* If PTR points to what *might* be a 16-bit branch or jump, then
+ return the minimum length of its delay slot, otherwise return 0.
+ Non-zero results are not definitive as we might be checking against
+ the second half of another instruction. */
+
+static int
+check_br16_dslot (bfd *abfd, bfd_byte *ptr)
+{
+ unsigned long opcode;
+ int bdsize;
+
+ opcode = bfd_get_16 (abfd, ptr);
+ if (MATCH (opcode, jalr_insn_16_bd32) != 0)
+ /* 16-bit branch/jump with a 32-bit delay slot. */
+ bdsize = 4;
+ else if (MATCH (opcode, jalr_insn_16_bd16) != 0
+ || find_match (opcode, ds_insns_16_bd16) >= 0)
+ /* 16-bit branch/jump with a 16-bit delay slot. */
+ bdsize = 2;
+ else
+ /* No delay slot. */
+ bdsize = 0;
+
+ return bdsize;
+}
+
+/* If PTR points to what *might* be a 32-bit branch or jump, then
+ return the minimum length of its delay slot, otherwise return 0.
+ Non-zero results are not definitive as we might be checking against
+ the second half of another instruction. */
+
+static int
+check_br32_dslot (bfd *abfd, bfd_byte *ptr)
+{
+ unsigned long opcode;
+ int bdsize;
+
+ opcode = bfd_get_micromips_32 (abfd, ptr);
+ if (find_match (opcode, ds_insns_32_bd32) >= 0)
+ /* 32-bit branch/jump with a 32-bit delay slot. */
+ bdsize = 4;
+ else if (find_match (opcode, ds_insns_32_bd16) >= 0)
+ /* 32-bit branch/jump with a 16-bit delay slot. */
+ bdsize = 2;
+ else
+ /* No delay slot. */
+ bdsize = 0;
+
+ return bdsize;
+}
+
+/* If PTR points to a 16-bit branch or jump with a 32-bit delay slot
+ that doesn't fiddle with REG, then return TRUE, otherwise FALSE. */
+
+static bfd_boolean
+check_br16 (bfd *abfd, bfd_byte *ptr, unsigned long reg)
+{
+ unsigned long opcode;
+
+ opcode = bfd_get_16 (abfd, ptr);
+ if (MATCH (opcode, b_insn_16)
+ /* B16 */
+ || (MATCH (opcode, jr_insn_16) && reg != JR16_REG (opcode))
+ /* JR16 */
+ || (MATCH (opcode, bz_insn_16) && reg != BZ16_REG (opcode))
+ /* BEQZ16, BNEZ16 */
+ || (MATCH (opcode, jalr_insn_16_bd32)
+ /* JALR16 */
+ && reg != JR16_REG (opcode) && reg != RA))
+ return TRUE;
+
+ return FALSE;
}
+/* If PTR points to a 32-bit branch or jump that doesn't fiddle with REG,
+ then return TRUE, otherwise FALSE. */
+
+static bfd_boolean
+check_br32 (bfd *abfd, bfd_byte *ptr, unsigned long reg)
+{
+ unsigned long opcode;
+
+ opcode = bfd_get_micromips_32 (abfd, ptr);
+ if (MATCH (opcode, j_insn_32)
+ /* J */
+ || MATCH (opcode, bc_insn_32)
+ /* BC1F, BC1T, BC2F, BC2T */
+ || (MATCH (opcode, jal_x_insn_32_bd32) && reg != RA)
+ /* JAL, JALX */
+ || (MATCH (opcode, bz_insn_32) && reg != OP32_SREG (opcode))
+ /* BGEZ, BGTZ, BLEZ, BLTZ */
+ || (MATCH (opcode, bzal_insn_32)
+ /* BGEZAL, BLTZAL */
+ && reg != OP32_SREG (opcode) && reg != RA)
+ || ((MATCH (opcode, jalr_insn_32) || MATCH (opcode, beq_insn_32))
+ /* JALR, JALR.HB, BEQ, BNE */
+ && reg != OP32_SREG (opcode) && reg != OP32_TREG (opcode)))
+ return TRUE;
+
+ return FALSE;
+}
+
+/* If the instruction encoding at PTR and relocations [INTERNAL_RELOCS,
+ IRELEND) at OFFSET indicate that there must be a compact branch there,
+ then return TRUE, otherwise FALSE. */
+
+static bfd_boolean
+check_relocated_bzc (bfd *abfd, const bfd_byte *ptr, bfd_vma offset,
+ const Elf_Internal_Rela *internal_relocs,
+ const Elf_Internal_Rela *irelend)
+{
+ const Elf_Internal_Rela *irel;
+ unsigned long opcode;
+
+ opcode = bfd_get_micromips_32 (abfd, ptr);
+ if (find_match (opcode, bzc_insns_32) < 0)
+ return FALSE;
+
+ for (irel = internal_relocs; irel < irelend; irel++)
+ if (irel->r_offset == offset
+ && ELF32_R_TYPE (irel->r_info) == R_MICROMIPS_PC16_S1)
+ return TRUE;
+
+ return FALSE;
+}
+
+/* Bitsize checking. */
+#define IS_BITSIZE(val, N) \
+ (((((val) & ((1ULL << (N)) - 1)) ^ (1ULL << ((N) - 1))) \
+ - (1ULL << ((N) - 1))) == (val))
+
+\f
+bfd_boolean
+_bfd_mips_elf_relax_section (bfd *abfd, asection *sec,
+ struct bfd_link_info *link_info,
+ bfd_boolean *again)
+{
+ Elf_Internal_Shdr *symtab_hdr;
+ Elf_Internal_Rela *internal_relocs;
+ Elf_Internal_Rela *irel, *irelend;
+ bfd_byte *contents = NULL;
+ Elf_Internal_Sym *isymbuf = NULL;
+
+ /* Assume nothing changes. */
+ *again = FALSE;
+
+ /* We don't have to do anything for a relocatable link, if
+ this section does not have relocs, or if this is not a
+ code section. */
+
+ if (link_info->relocatable
+ || (sec->flags & SEC_RELOC) == 0
+ || sec->reloc_count == 0
+ || (sec->flags & SEC_CODE) == 0)
+ return TRUE;
+
+ symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+
+ /* Get a copy of the native relocations. */
+ internal_relocs = (_bfd_elf_link_read_relocs
+ (abfd, sec, NULL, (Elf_Internal_Rela *) NULL,
+ link_info->keep_memory));
+ if (internal_relocs == NULL)
+ goto error_return;
+
+ /* Walk through them looking for relaxing opportunities. */
+ irelend = internal_relocs + sec->reloc_count;
+ for (irel = internal_relocs; irel < irelend; irel++)
+ {
+ unsigned long r_symndx = ELF32_R_SYM (irel->r_info);
+ unsigned int r_type = ELF32_R_TYPE (irel->r_info);
+ bfd_boolean target_is_micromips_code_p;
+ unsigned long opcode;
+ bfd_vma symval;
+ bfd_vma pcrval;
+ bfd_byte *ptr;
+ int fndopc;
+
+ /* The number of bytes to delete for relaxation and from where
+ to delete these bytes starting at irel->r_offset. */
+ int delcnt = 0;
+ int deloff = 0;
+
+ /* If this isn't something that can be relaxed, then ignore
+ this reloc. */
+ if (r_type != R_MICROMIPS_HI16
+ && r_type != R_MICROMIPS_PC16_S1
+ && r_type != R_MICROMIPS_26_S1)
+ continue;
+
+ /* Get the section contents if we haven't done so already. */
+ if (contents == NULL)
+ {
+ /* Get cached copy if it exists. */
+ if (elf_section_data (sec)->this_hdr.contents != NULL)
+ contents = elf_section_data (sec)->this_hdr.contents;
+ /* Go get them off disk. */
+ else if (!bfd_malloc_and_get_section (abfd, sec, &contents))
+ goto error_return;
+ }
+ ptr = contents + irel->r_offset;
+
+ /* Read this BFD's local symbols if we haven't done so already. */
+ if (isymbuf == NULL && symtab_hdr->sh_info != 0)
+ {
+ isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
+ if (isymbuf == NULL)
+ isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
+ symtab_hdr->sh_info, 0,
+ NULL, NULL, NULL);
+ if (isymbuf == NULL)
+ goto error_return;
+ }
+
+ /* Get the value of the symbol referred to by the reloc. */
+ if (r_symndx < symtab_hdr->sh_info)
+ {
+ /* A local symbol. */
+ Elf_Internal_Sym *isym;
+ asection *sym_sec;
+
+ isym = isymbuf + r_symndx;
+ if (isym->st_shndx == SHN_UNDEF)
+ sym_sec = bfd_und_section_ptr;
+ else if (isym->st_shndx == SHN_ABS)
+ sym_sec = bfd_abs_section_ptr;
+ else if (isym->st_shndx == SHN_COMMON)
+ sym_sec = bfd_com_section_ptr;
+ else
+ sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
+ symval = (isym->st_value
+ + sym_sec->output_section->vma
+ + sym_sec->output_offset);
+ target_is_micromips_code_p = ELF_ST_IS_MICROMIPS (isym->st_other);
+ }
+ else
+ {
+ unsigned long indx;
+ struct elf_link_hash_entry *h;
+
+ /* An external symbol. */
+ indx = r_symndx - symtab_hdr->sh_info;
+ h = elf_sym_hashes (abfd)[indx];
+ BFD_ASSERT (h != NULL);
+
+ if (h->root.type != bfd_link_hash_defined
+ && h->root.type != bfd_link_hash_defweak)
+ /* This appears to be a reference to an undefined
+ symbol. Just ignore it -- it will be caught by the
+ regular reloc processing. */
+ continue;
+
+ symval = (h->root.u.def.value
+ + h->root.u.def.section->output_section->vma
+ + h->root.u.def.section->output_offset);
+ target_is_micromips_code_p = (!h->needs_plt
+ && ELF_ST_IS_MICROMIPS (h->other));
+ }
+
+
+ /* For simplicity of coding, we are going to modify the
+ section contents, the section relocs, and the BFD symbol
+ table. We must tell the rest of the code not to free up this
+ information. It would be possible to instead create a table
+ of changes which have to be made, as is done in coff-mips.c;
+ that would be more work, but would require less memory when
+ the linker is run. */
+
+ /* Only 32-bit instructions relaxed. */
+ if (irel->r_offset + 4 > sec->size)
+ continue;
+
+ opcode = bfd_get_micromips_32 (abfd, ptr);
+
+ /* This is the pc-relative distance from the instruction the
+ relocation is applied to, to the symbol referred. */
+ pcrval = (symval
+ - (sec->output_section->vma + sec->output_offset)
+ - irel->r_offset);
+
+ /* R_MICROMIPS_HI16 / LUI relaxation to nil, performing relaxation
+ of corresponding R_MICROMIPS_LO16 to R_MICROMIPS_HI0_LO16 or
+ R_MICROMIPS_PC23_S2. The R_MICROMIPS_PC23_S2 condition is
+
+ (symval % 4 == 0 && IS_BITSIZE (pcrval, 25))
+
+ where pcrval has first to be adjusted to apply against the LO16
+ location (we make the adjustment later on, when we have figured
+ out the offset). */
+ if (r_type == R_MICROMIPS_HI16 && MATCH (opcode, lui_insn))
+ {
+ bfd_boolean bzc = FALSE;
+ unsigned long nextopc;
+ unsigned long reg;
+ bfd_vma offset;
+
+ /* Give up if the previous reloc was a HI16 against this symbol
+ too. */
+ if (irel > internal_relocs
+ && ELF32_R_TYPE (irel[-1].r_info) == R_MICROMIPS_HI16
+ && ELF32_R_SYM (irel[-1].r_info) == r_symndx)
+ continue;
+
+ /* Or if the next reloc is not a LO16 against this symbol. */
+ if (irel + 1 >= irelend
+ || ELF32_R_TYPE (irel[1].r_info) != R_MICROMIPS_LO16
+ || ELF32_R_SYM (irel[1].r_info) != r_symndx)
+ continue;
+
+ /* Or if the second next reloc is a LO16 against this symbol too. */
+ if (irel + 2 >= irelend
+ && ELF32_R_TYPE (irel[2].r_info) == R_MICROMIPS_LO16
+ && ELF32_R_SYM (irel[2].r_info) == r_symndx)
+ continue;
+
+ /* See if the LUI instruction *might* be in a branch delay slot.
+ We check whether what looks like a 16-bit branch or jump is
+ actually an immediate argument to a compact branch, and let
+ it through if so. */
+ if (irel->r_offset >= 2
+ && check_br16_dslot (abfd, ptr - 2)
+ && !(irel->r_offset >= 4
+ && (bzc = check_relocated_bzc (abfd,
+ ptr - 4, irel->r_offset - 4,
+ internal_relocs, irelend))))
+ continue;
+ if (irel->r_offset >= 4
+ && !bzc
+ && check_br32_dslot (abfd, ptr - 4))
+ continue;
+
+ reg = OP32_SREG (opcode);
+
+ /* We only relax adjacent instructions or ones separated with
+ a branch or jump that has a delay slot. The branch or jump
+ must not fiddle with the register used to hold the address.
+ Subtract 4 for the LUI itself. */
+ offset = irel[1].r_offset - irel[0].r_offset;
+ switch (offset - 4)
+ {
+ case 0:
+ break;
+ case 2:
+ if (check_br16 (abfd, ptr + 4, reg))
+ break;
+ continue;
+ case 4:
+ if (check_br32 (abfd, ptr + 4, reg))
+ break;
+ continue;
+ default:
+ continue;
+ }
+
+ nextopc = bfd_get_micromips_32 (abfd, contents + irel[1].r_offset);
+
+ /* Give up unless the same register is used with both
+ relocations. */
+ if (OP32_SREG (nextopc) != reg)
+ continue;
+
+ /* Now adjust pcrval, subtracting the offset to the LO16 reloc
+ and rounding up to take masking of the two LSBs into account. */
+ pcrval = ((pcrval - offset + 3) | 3) ^ 3;
+
+ /* R_MICROMIPS_LO16 relaxation to R_MICROMIPS_HI0_LO16. */
+ if (IS_BITSIZE (symval, 16))
+ {
+ /* Fix the relocation's type. */
+ irel[1].r_info = ELF32_R_INFO (r_symndx, R_MICROMIPS_HI0_LO16);
+
+ /* Instructions using R_MICROMIPS_LO16 have the base or
+ source register in bits 20:16. This register becomes $0
+ (zero) as the result of the R_MICROMIPS_HI16 being 0. */
+ nextopc &= ~0x001f0000;
+ bfd_put_16 (abfd, (nextopc >> 16) & 0xffff,
+ contents + irel[1].r_offset);
+ }
+
+ /* R_MICROMIPS_LO16 / ADDIU relaxation to R_MICROMIPS_PC23_S2.
+ We add 4 to take LUI deletion into account while checking
+ the PC-relative distance. */
+ else if (symval % 4 == 0
+ && IS_BITSIZE (pcrval + 4, 25)
+ && MATCH (nextopc, addiu_insn)
+ && OP32_TREG (nextopc) == OP32_SREG (nextopc)
+ && OP16_VALID_REG (OP32_TREG (nextopc)))
+ {
+ /* Fix the relocation's type. */
+ irel[1].r_info = ELF32_R_INFO (r_symndx, R_MICROMIPS_PC23_S2);
+
+ /* Replace ADDIU with the ADDIUPC version. */
+ nextopc = (addiupc_insn.match
+ | ADDIUPC_REG_FIELD (OP32_TREG (nextopc)));
+
+ bfd_put_micromips_32 (abfd, nextopc,
+ contents + irel[1].r_offset);
+ }
+
+ /* Can't do anything, give up, sigh... */
+ else
+ continue;
+
+ /* Fix the relocation's type. */
+ irel->r_info = ELF32_R_INFO (r_symndx, R_MIPS_NONE);
+
+ /* Delete the LUI instruction: 4 bytes at irel->r_offset. */
+ delcnt = 4;
+ deloff = 0;
+ }
+
+ /* Compact branch relaxation -- due to the multitude of macros
+ employed by the compiler/assembler, compact branches are not
+ always generated. Obviously, this can/will be fixed elsewhere,
+ but there is no drawback in double checking it here. */
+ else if (r_type == R_MICROMIPS_PC16_S1
+ && irel->r_offset + 5 < sec->size
+ && ((fndopc = find_match (opcode, bz_rs_insns_32)) >= 0
+ || (fndopc = find_match (opcode, bz_rt_insns_32)) >= 0)
+ && MATCH (bfd_get_16 (abfd, ptr + 4), nop_insn_16))
+ {
+ unsigned long reg;
+
+ reg = OP32_SREG (opcode) ? OP32_SREG (opcode) : OP32_TREG (opcode);
+
+ /* Replace BEQZ/BNEZ with the compact version. */
+ opcode = (bzc_insns_32[fndopc].match
+ | BZC32_REG_FIELD (reg)
+ | (opcode & 0xffff)); /* Addend value. */
+
+ bfd_put_micromips_32 (abfd, opcode, ptr);
+
+ /* Delete the 16-bit delay slot NOP: two bytes from
+ irel->offset + 4. */
+ delcnt = 2;
+ deloff = 4;
+ }
+
+ /* R_MICROMIPS_PC16_S1 relaxation to R_MICROMIPS_PC10_S1. We need
+ to check the distance from the next instruction, so subtract 2. */
+ else if (r_type == R_MICROMIPS_PC16_S1
+ && IS_BITSIZE (pcrval - 2, 11)
+ && find_match (opcode, b_insns_32) >= 0)
+ {
+ /* Fix the relocation's type. */
+ irel->r_info = ELF32_R_INFO (r_symndx, R_MICROMIPS_PC10_S1);
+
+ /* Replace the 32-bit opcode with a 16-bit opcode. */
+ bfd_put_16 (abfd,
+ (b_insn_16.match
+ | (opcode & 0x3ff)), /* Addend value. */
+ ptr);
+
+ /* Delete 2 bytes from irel->r_offset + 2. */
+ delcnt = 2;
+ deloff = 2;
+ }
+
+ /* R_MICROMIPS_PC16_S1 relaxation to R_MICROMIPS_PC7_S1. We need
+ to check the distance from the next instruction, so subtract 2. */
+ else if (r_type == R_MICROMIPS_PC16_S1
+ && IS_BITSIZE (pcrval - 2, 8)
+ && (((fndopc = find_match (opcode, bz_rs_insns_32)) >= 0
+ && OP16_VALID_REG (OP32_SREG (opcode)))
+ || ((fndopc = find_match (opcode, bz_rt_insns_32)) >= 0
+ && OP16_VALID_REG (OP32_TREG (opcode)))))
+ {
+ unsigned long reg;
+
+ reg = OP32_SREG (opcode) ? OP32_SREG (opcode) : OP32_TREG (opcode);
+
+ /* Fix the relocation's type. */
+ irel->r_info = ELF32_R_INFO (r_symndx, R_MICROMIPS_PC7_S1);
+
+ /* Replace the 32-bit opcode with a 16-bit opcode. */
+ bfd_put_16 (abfd,
+ (bz_insns_16[fndopc].match
+ | BZ16_REG_FIELD (reg)
+ | (opcode & 0x7f)), /* Addend value. */
+ ptr);
+
+ /* Delete 2 bytes from irel->r_offset + 2. */
+ delcnt = 2;
+ deloff = 2;
+ }
+
+ /* R_MICROMIPS_26_S1 -- JAL to JALS relaxation for microMIPS targets. */
+ else if (r_type == R_MICROMIPS_26_S1
+ && target_is_micromips_code_p
+ && irel->r_offset + 7 < sec->size
+ && MATCH (opcode, jal_insn_32_bd32))
+ {
+ unsigned long n32opc;
+ bfd_boolean relaxed = FALSE;
+
+ n32opc = bfd_get_micromips_32 (abfd, ptr + 4);
+
+ if (MATCH (n32opc, nop_insn_32))
+ {
+ /* Replace delay slot 32-bit NOP with a 16-bit NOP. */
+ bfd_put_16 (abfd, nop_insn_16.match, ptr + 4);
+
+ relaxed = TRUE;
+ }
+ else if (find_match (n32opc, move_insns_32) >= 0)
+ {
+ /* Replace delay slot 32-bit MOVE with 16-bit MOVE. */
+ bfd_put_16 (abfd,
+ (move_insn_16.match
+ | MOVE16_RD_FIELD (MOVE32_RD (n32opc))
+ | MOVE16_RS_FIELD (MOVE32_RS (n32opc))),
+ ptr + 4);
+
+ relaxed = TRUE;
+ }
+ /* Other 32-bit instructions relaxable to 16-bit
+ instructions will be handled here later. */
+
+ if (relaxed)
+ {
+ /* JAL with 32-bit delay slot that is changed to a JALS
+ with 16-bit delay slot. */
+ bfd_put_micromips_32 (abfd, jal_insn_32_bd16.match, ptr);
+
+ /* Delete 2 bytes from irel->r_offset + 6. */
+ delcnt = 2;
+ deloff = 6;
+ }
+ }
+
+ if (delcnt != 0)
+ {
+ /* Note that we've changed the relocs, section contents, etc. */
+ elf_section_data (sec)->relocs = internal_relocs;
+ elf_section_data (sec)->this_hdr.contents = contents;
+ symtab_hdr->contents = (unsigned char *) isymbuf;
+
+ /* Delete bytes depending on the delcnt and deloff. */
+ if (!mips_elf_relax_delete_bytes (abfd, sec,
+ irel->r_offset + deloff, delcnt))
+ goto error_return;
+
+ /* That will change things, so we should relax again.
+ Note that this is not required, and it may be slow. */
+ *again = TRUE;
+ }
+ }
+
+ if (isymbuf != NULL
+ && symtab_hdr->contents != (unsigned char *) isymbuf)
+ {
+ if (! link_info->keep_memory)
+ free (isymbuf);
+ else
+ {
+ /* Cache the symbols for elf_link_input_bfd. */
+ symtab_hdr->contents = (unsigned char *) isymbuf;
+ }
+ }
+
+ if (contents != NULL
+ && elf_section_data (sec)->this_hdr.contents != contents)
+ {
+ if (! link_info->keep_memory)
+ free (contents);
+ else
+ {
+ /* Cache the section contents for elf_link_input_bfd. */
+ elf_section_data (sec)->this_hdr.contents = contents;
+ }
+ }
+
+ if (internal_relocs != NULL
+ && elf_section_data (sec)->relocs != internal_relocs)
+ free (internal_relocs);
+
+ return TRUE;
+
+ error_return:
+ if (isymbuf != NULL
+ && symtab_hdr->contents != (unsigned char *) isymbuf)
+ free (isymbuf);
+ if (contents != NULL
+ && elf_section_data (sec)->this_hdr.contents != contents)
+ free (contents);
+ if (internal_relocs != NULL
+ && elf_section_data (sec)->relocs != internal_relocs)
+ free (internal_relocs);
+
+ return FALSE;
+}
+\f
/* Create a MIPS ELF linker hash table. */
struct bfd_link_hash_table *
if (!_bfd_elf_link_hash_table_init (&ret->root, abfd,
mips_elf_link_hash_newfunc,
- sizeof (struct mips_elf_link_hash_entry)))
+ sizeof (struct mips_elf_link_hash_entry),
+ MIPS_ELF_DATA))
{
free (ret);
return NULL;
ret->procedure_count = 0;
ret->compact_rel_size = 0;
ret->use_rld_obj_head = FALSE;
- ret->rld_value = 0;
+ ret->rld_symbol = NULL;
ret->mips16_stubs_seen = FALSE;
ret->use_plts_and_copy_relocs = FALSE;
ret->is_vxworks = FALSE;
/* Sort the dynamic symbols so that those with GOT entries come after
those without. */
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
if (!mips_elf_sort_hash_table (abfd, info))
return FALSE;
if (SGI_COMPAT (abfd) && info->shared)
{
/* Create .rtproc section. */
- rtproc_sec = bfd_get_section_by_name (abfd, ".rtproc");
+ rtproc_sec = bfd_get_linker_section (abfd, ".rtproc");
if (rtproc_sec == NULL)
{
flagword flags = (SEC_HAS_CONTENTS | SEC_IN_MEMORY
| SEC_LINKER_CREATED | SEC_READONLY);
- rtproc_sec = bfd_make_section_with_flags (abfd,
- ".rtproc",
- flags);
+ rtproc_sec = bfd_make_section_anyway_with_flags (abfd,
+ ".rtproc",
+ flags);
if (rtproc_sec == NULL
|| ! bfd_set_section_alignment (abfd, rtproc_sec, 4))
return FALSE;
static const struct mips_mach_extension mips_mach_extensions[] = {
/* MIPS64r2 extensions. */
+ { bfd_mach_mips_octeon2, bfd_mach_mips_octeonp },
+ { bfd_mach_mips_octeonp, bfd_mach_mips_octeon },
{ bfd_mach_mips_octeon, bfd_mach_mipsisa64r2 },
/* MIPS64 extensions. */
{ bfd_mach_mipsisa64r2, bfd_mach_mipsisa64 },
{ bfd_mach_mips_sb1, bfd_mach_mipsisa64 },
{ bfd_mach_mips_xlr, bfd_mach_mipsisa64 },
+ { bfd_mach_mips_loongson_3a, bfd_mach_mipsisa64 },
/* MIPS V extensions. */
{ bfd_mach_mipsisa64, bfd_mach_mips5 },
bfd_boolean null_input_bfd = TRUE;
asection *sec;
- /* Check if we have the same endianess */
+ /* Check if we have the same endianness. */
if (! _bfd_generic_verify_endian_match (ibfd, obfd))
{
(*_bfd_error_handler)
for (sec = ibfd->sections; sec != NULL; sec = sec->next)
{
/* Ignore synthetic sections and empty .text, .data and .bss sections
- which are automatically generated by gas. */
- if (strcmp (sec->name, ".reginfo")
+ which are automatically generated by gas. Also ignore fake
+ (s)common sections, since merely defining a common symbol does
+ not affect compatibility. */
+ if ((sec->flags & SEC_IS_COMMON) == 0
+ && strcmp (sec->name, ".reginfo")
&& strcmp (sec->name, ".mdebug")
&& (sec->size != 0
|| (strcmp (sec->name, ".text")
old_flags &= ~EF_MIPS_ABI;
}
- /* For now, allow arbitrary mixing of ASEs (retain the union). */
+ /* Compare ASEs. Forbid linking MIPS16 and microMIPS ASE modules together
+ and allow arbitrary mixing of the remaining ASEs (retain the union). */
if ((new_flags & EF_MIPS_ARCH_ASE) != (old_flags & EF_MIPS_ARCH_ASE))
{
+ int old_micro = old_flags & EF_MIPS_ARCH_ASE_MICROMIPS;
+ int new_micro = new_flags & EF_MIPS_ARCH_ASE_MICROMIPS;
+ int old_m16 = old_flags & EF_MIPS_ARCH_ASE_M16;
+ int new_m16 = new_flags & EF_MIPS_ARCH_ASE_M16;
+ int micro_mis = old_m16 && new_micro;
+ int m16_mis = old_micro && new_m16;
+
+ if (m16_mis || micro_mis)
+ {
+ (*_bfd_error_handler)
+ (_("%B: ASE mismatch: linking %s module with previous %s modules"),
+ ibfd,
+ m16_mis ? "MIPS16" : "microMIPS",
+ m16_mis ? "microMIPS" : "MIPS16");
+ ok = FALSE;
+ }
+
elf_elfheader (obfd)->e_flags |= new_flags & EF_MIPS_ARCH_ASE;
new_flags &= ~ EF_MIPS_ARCH_ASE;
if (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_M16)
fprintf (file, " [mips16]");
+ if (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_MICROMIPS)
+ fprintf (file, " [micromips]");
+
if (elf_elfheader (abfd)->e_flags & EF_MIPS_32BITMODE)
fprintf (file, " [32bitmode]");
else
if (link_info)
{
htab = mips_elf_hash_table (link_info);
+ BFD_ASSERT (htab != NULL);
+
if (htab->use_plts_and_copy_relocs && !htab->is_vxworks)
i_ehdrp->e_ident[EI_ABIVERSION] = 1;
}