/* MIPS-specific support for ELF
Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
- 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
+ 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,
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;
|| r_type == R_MIPS_TLS_TPREL64 \
|| r_type == R_MIPS_TLS_TPREL_HI16 \
|| r_type == R_MIPS_TLS_TPREL_LO16 \
+ || r_type == R_MIPS16_TLS_GD \
+ || r_type == R_MIPS16_TLS_LDM \
+ || r_type == R_MIPS16_TLS_DTPREL_HI16 \
+ || r_type == R_MIPS16_TLS_DTPREL_LO16 \
+ || r_type == R_MIPS16_TLS_GOTTPREL \
+ || r_type == R_MIPS16_TLS_TPREL_HI16 \
+ || r_type == R_MIPS16_TLS_TPREL_LO16 \
|| r_type == R_MICROMIPS_TLS_GD \
|| r_type == R_MICROMIPS_TLS_LDM \
|| r_type == R_MICROMIPS_TLS_DTPREL_HI16 \
#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)
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 */
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);
}
/* 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. */
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)
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;
*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)
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:
static inline bfd_boolean
tls_gd_reloc_p (unsigned int r_type)
{
- return r_type == R_MIPS_TLS_GD || r_type == R_MICROMIPS_TLS_GD;
+ 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_MICROMIPS_TLS_LDM;
+ 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_MICROMIPS_TLS_GOTTPREL;
+ return (r_type == R_MIPS_TLS_GOTTPREL
+ || r_type == R_MIPS16_TLS_GOTTPREL
+ || r_type == R_MICROMIPS_TLS_GOTTPREL);
}
void
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_PC23_S2:
return TRUE;
+ case R_MIPS16_26:
+ return !target_is_16_bit_code_p;
+
default:
return FALSE;
}
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);
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:
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);
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;
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. */
/* 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;
case R_MIPS_TLS_GOTTPREL:
case R_MIPS_TLS_LDM:
case R_MIPS_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 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;
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
if (! bfd_elf_link_record_dynamic_symbol (info, h))
return FALSE;
+ mips_elf_hash_table (info)->rld_symbol = h;
}
}
/* 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:
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)
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:
+ case R_MIPS16_TLS_LDM:
case R_MICROMIPS_TLS_LDM:
if (tls_ldm_reloc_p (r_type))
{
/* 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. */
{
/* 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"))
}
}
+/* 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
sec = h->root.u.def.section;
}
- if (sec != NULL && elf_discarded_section (sec))
- RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
- rel, relend, howto, contents);
+ if (sec != NULL && discarded_section (sec))
+ {
+ mips_reloc_against_discarded_section (output_bfd, info, input_bfd,
+ input_section, &rel, &relend,
+ rel_reloc, howto, contents);
+ continue;
+ }
if (r_type == R_MIPS_64 && ! NEWABI_P (input_bfd))
{
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 (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))
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:
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;
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,
&elf_tdata (abfd)->dwarf2_find_line_info))
{ /* "b", "mD", */ 0xcc00, 0xfc00 };
static const struct opcode_descriptor bz_insn_16 =
- { /* "b(eq|ne)z", "md,mE", */ 0x8c00, 0xac00 };
+ { /* "b(eq|ne)z", "md,mE", */ 0x8c00, 0xdc00 };
/* 32-bit and 16-bit branch EQ and NE zero. */
/* If PTR points to a 32-bit branch or jump that doesn't fiddle with REG,
then return TRUE, otherwise FALSE. */
-static int
+static bfd_boolean
check_br32 (bfd *abfd, bfd_byte *ptr, unsigned long reg)
{
unsigned long opcode;
return FALSE;
}
-/* Bitsize checking. */
-#define IS_BITSIZE(val, N) \
- (((((val) & ((1ULL << (N)) - 1)) ^ (1ULL << ((N) - 1))) \
- - (1ULL << ((N) - 1))) == (val))
-
-/* See if relocations [INTERNAL_RELOCS, IRELEND) confirm that there
- is a 4-byte branch at offset OFFSET. */
+/* 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_4byte_branch (Elf_Internal_Rela *internal_relocs,
- Elf_Internal_Rela *irelend, bfd_vma offset)
+check_relocated_bzc (bfd *abfd, const bfd_byte *ptr, bfd_vma offset,
+ const Elf_Internal_Rela *internal_relocs,
+ const Elf_Internal_Rela *irelend)
{
- Elf_Internal_Rela *irel;
- unsigned long r_type;
+ const Elf_Internal_Rela *irel;
+ unsigned long opcode;
+
+ opcode = bfd_get_16 (abfd, ptr);
+ opcode <<= 16;
+ opcode |= bfd_get_16 (abfd, ptr + 2);
+ if (find_match (opcode, bzc_insns_32) < 0)
+ return FALSE;
for (irel = internal_relocs; irel < irelend; irel++)
- if (irel->r_offset == offset)
- {
- r_type = ELF32_R_TYPE (irel->r_info);
- if (r_type == R_MICROMIPS_26_S1
- || r_type == R_MICROMIPS_PC16_S1
- || r_type == R_MICROMIPS_JALR)
- return TRUE;
- }
+ 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,
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;
&& ELF32_R_SYM (irel[2].r_info) == r_symndx)
continue;
- /* See if the LUI instruction *might* be in a branch delay slot. */
+ /* 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
- /* If the instruction is actually a 4-byte branch,
- the value of check_br16_dslot doesn't matter.
- We should use check_br32_dslot to check whether
- the branch has a delay slot. */
- && check_4byte_branch (internal_relocs, irelend,
- 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;
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;
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. */