/* 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, 2013
Free Software Foundation, Inc.
Most of the information added by Ian Lance Taylor, Cygnus Support,
#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_1(VAL) (0x41b9) /* lui t9,VAL */
-#define LA25_LUI_MICROMIPS_2(VAL) (VAL)
-#define LA25_J_MICROMIPS_1(VAL) (0xd400 | (((VAL) >> 17) & 0x3ff)) /* j VAL */
-#define LA25_J_MICROMIPS_2(VAL) ((VAL) >> 1)
-#define LA25_ADDIU_MICROMIPS_1(VAL) (0x3339) /* addiu t9,t9,VAL */
-#define LA25_ADDIU_MICROMIPS_2(VAL) (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 size of the .compact_rel section (if SGI_COMPAT). */
bfd_size_type compact_rel_size;
- /* This flag indicates that the value of DT_MIPS_RLD_MAP dynamic
- entry is set to the address of __rld_obj_head as in IRIX5. */
+ /* This flag indicates that the value of DT_MIPS_RLD_MAP dynamic entry
+ is set to the address of __rld_obj_head as in IRIX5 and IRIX6. */
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;
bfd_boolean error;
};
+/* MIPS ELF private object data. */
+
+struct mips_elf_obj_tdata
+{
+ /* Generic ELF private object data. */
+ struct elf_obj_tdata root;
+
+ /* Input BFD providing Tag_GNU_MIPS_ABI_FP attribute for output. */
+ bfd *abi_fp_bfd;
+};
+
+/* Get MIPS ELF private object data from BFD's tdata. */
+
+#define mips_elf_tdata(bfd) \
+ ((struct mips_elf_obj_tdata *) (bfd)->tdata.any)
+
#define TLS_RELOC_P(r_type) \
(r_type == R_MIPS_TLS_DTPMOD32 \
|| r_type == R_MIPS_TLS_DTPMOD64 \
|| r_type == R_MIPS_TLS_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 */
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) \
return (struct bfd_hash_entry *) ret;
}
+/* Allocate MIPS ELF private object data. */
+
+bfd_boolean
+_bfd_mips_elf_mkobject (bfd *abfd)
+{
+ return bfd_elf_allocate_object (abfd, sizeof (struct mips_elf_obj_tdata),
+ MIPS_ELF_DATA);
+}
+
bfd_boolean
_bfd_mips_elf_new_section_hook (bfd *abfd, asection *sec)
{
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
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)))
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)))
/* 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_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 (h->call_stub != NULL && h->call_fp_stub != NULL)
{
asection *o;
-
+
sec = NULL;
for (o = input_bfd->sections; o != NULL; o = o->next)
{
/* 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);
&& (target_is_16_bit_code_p
|| target_is_micromips_code_p))));
- local_p = h == NULL || SYMBOL_REFERENCES_LOCAL (info, &h->root);
+ 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);
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:
/* 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.
+ 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.
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: Direct jumps between ISA modes are not allowed; consider recompiling with interlinking enabled."),
+ (_("%B: %A+0x%lx: Unsupported jump between ISA modes; consider recompiling with interlinking enabled."),
input_bfd,
input_section,
(unsigned long) relocation->r_offset);
/* 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_5500:
return bfd_mach_mips5500;
+ case E_MIPS_MACH_5900:
+ return bfd_mach_mips5900;
+
case E_MIPS_MACH_9000:
return bfd_mach_mips9000;
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
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)))
return FALSE;
htab->sstubs = s;
- if ((IRIX_COMPAT (abfd) == ict_irix5 || IRIX_COMPAT (abfd) == ict_none)
+ if (!mips_elf_hash_table (info)->use_rld_obj_head
&& !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
/* 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)
{
h = ((struct mips_elf_link_hash_entry *)
sym_hashes[r_symndx - extsymoff]);
-
+
/* H is the symbol this stub is for. */
-
+
if (CALL_FP_STUB_P (name))
loc = &h->call_fp_stub;
else
loc = &h->call_stub;
-
+
/* If we already have an appropriate stub for this function, we
don't need another one, so we can discard this one. Since
this function is called before the linker maps input sections
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. */
if (! info->relocatable
&& hmips->possibly_dynamic_relocs != 0
&& (h->root.type == bfd_link_hash_defweak
- || !h->def_regular
+ || (!h->def_regular && !ELF_COMMON_DEF_P (h))
|| info->shared))
{
bfd_boolean do_copy = TRUE;
/* 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. */
/* 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;
}
}
}
+/* 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);
loc += offset;
if (ELF_ST_IS_MICROMIPS (stub->h->root.other))
{
- bfd_put_16 (hti->output_bfd, LA25_LUI_MICROMIPS_1 (target_high),
- loc);
- bfd_put_16 (hti->output_bfd, LA25_LUI_MICROMIPS_2 (target_high),
- loc + 2);
- bfd_put_16 (hti->output_bfd, LA25_ADDIU_MICROMIPS_1 (target_low),
- loc + 4);
- bfd_put_16 (hti->output_bfd, LA25_ADDIU_MICROMIPS_2 (target_low),
- loc + 6);
+ 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
{
loc += offset;
if (ELF_ST_IS_MICROMIPS (stub->h->root.other))
{
- bfd_put_16 (hti->output_bfd, LA25_LUI_MICROMIPS_1 (target_high),
- loc);
- bfd_put_16 (hti->output_bfd, LA25_LUI_MICROMIPS_2 (target_high),
- loc + 2);
- bfd_put_16 (hti->output_bfd, LA25_J_MICROMIPS_1 (target), loc + 4);
- bfd_put_16 (hti->output_bfd, LA25_J_MICROMIPS_2 (target), loc + 6);
- bfd_put_16 (hti->output_bfd, LA25_ADDIU_MICROMIPS_1 (target_low),
- loc + 8);
- bfd_put_16 (hti->output_bfd, LA25_ADDIU_MICROMIPS_2 (target_low),
- loc + 10);
+ 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
/* 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))
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_4 | E_MIPS_MACH_5500;
break;
+ case bfd_mach_mips5900:
+ val = E_MIPS_ARCH_3 | E_MIPS_MACH_5900;
+ break;
+
case bfd_mach_mips9000:
val = E_MIPS_ARCH_4 | E_MIPS_MACH_9000;
break;
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,
+ line_ptr, NULL, ABI_64_P (abfd) ? 8 : 0,
&elf_tdata (abfd)->dwarf2_find_line_info))
return TRUE;
{ /* "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. */
unsigned long opcode;
int bdsize;
- opcode = (bfd_get_16 (abfd, ptr) << 16) | bfd_get_16 (abfd, ptr + 2);
+ 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;
/* 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;
- opcode = (bfd_get_16 (abfd, ptr) << 16) | bfd_get_16 (abfd, ptr + 2);
+ opcode = bfd_get_micromips_32 (abfd, ptr);
if (MATCH (opcode, j_insn_32)
/* J */
|| MATCH (opcode, bc_insn_32)
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_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)
- {
- 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,
/* Get a copy of the native relocations. */
internal_relocs = (_bfd_elf_link_read_relocs
- (abfd, sec, (PTR) NULL, (Elf_Internal_Rela *) NULL,
+ (abfd, sec, NULL, (Elf_Internal_Rela *) NULL,
link_info->keep_memory));
if (internal_relocs == NULL)
goto error_return;
if (irel->r_offset + 4 > sec->size)
continue;
- opcode = bfd_get_16 (abfd, ptr ) << 16;
- opcode |= bfd_get_16 (abfd, ptr + 2);
+ 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. */
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;
continue;
}
- nextopc = bfd_get_16 (abfd, contents + irel[1].r_offset ) << 16;
- nextopc |= bfd_get_16 (abfd, contents + irel[1].r_offset + 2);
+ nextopc = bfd_get_micromips_32 (abfd, contents + irel[1].r_offset);
/* Give up unless the same register is used with both
relocations. */
nextopc = (addiupc_insn.match
| ADDIUPC_REG_FIELD (OP32_TREG (nextopc)));
- bfd_put_16 (abfd, (nextopc >> 16) & 0xffff,
- contents + irel[1].r_offset);
- bfd_put_16 (abfd, nextopc & 0xffff,
- contents + irel[1].r_offset + 2);
+ bfd_put_micromips_32 (abfd, nextopc,
+ contents + irel[1].r_offset);
}
/* Can't do anything, give up, sigh... */
| BZC32_REG_FIELD (reg)
| (opcode & 0xffff)); /* Addend value. */
- bfd_put_16 (abfd, (opcode >> 16) & 0xffff, ptr);
- bfd_put_16 (abfd, opcode & 0xffff, ptr + 2);
+ bfd_put_micromips_32 (abfd, opcode, ptr);
/* Delete the 16-bit delay slot NOP: two bytes from
irel->offset + 4. */
/* Fix the relocation's type. */
irel->r_info = ELF32_R_INFO (r_symndx, R_MICROMIPS_PC10_S1);
- /* Replace the the 32-bit opcode with a 16-bit opcode. */
+ /* Replace the 32-bit opcode with a 16-bit opcode. */
bfd_put_16 (abfd,
(b_insn_16.match
| (opcode & 0x3ff)), /* Addend value. */
/* Fix the relocation's type. */
irel->r_info = ELF32_R_INFO (r_symndx, R_MICROMIPS_PC7_S1);
- /* Replace the the 32-bit opcode with a 16-bit opcode. */
+ /* Replace the 32-bit opcode with a 16-bit opcode. */
bfd_put_16 (abfd,
(bz_insns_16[fndopc].match
| BZ16_REG_FIELD (reg)
unsigned long n32opc;
bfd_boolean relaxed = FALSE;
- n32opc = bfd_get_16 (abfd, ptr + 4) << 16;
- n32opc |= bfd_get_16 (abfd, ptr + 6);
+ n32opc = bfd_get_micromips_32 (abfd, ptr + 4);
if (MATCH (n32opc, nop_insn_32))
{
{
/* JAL with 32-bit delay slot that is changed to a JALS
with 16-bit delay slot. */
- bfd_put_16 (abfd, (jal_insn_32_bd16.match >> 16) & 0xffff,
- ptr);
- bfd_put_16 (abfd, jal_insn_32_bd16.match & 0xffff,
- ptr + 2);
+ bfd_put_micromips_32 (abfd, jal_insn_32_bd16.match, ptr);
/* Delete 2 bytes from irel->r_offset + 6. */
delcnt = 2;
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;
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_mips4300, bfd_mach_mips4000 },
{ bfd_mach_mips4100, bfd_mach_mips4000 },
{ bfd_mach_mips4010, bfd_mach_mips4000 },
+ { bfd_mach_mips5900, bfd_mach_mips4000 },
/* MIPS32 extensions. */
{ bfd_mach_mipsisa32r2, bfd_mach_mipsisa32 },
{
obj_attribute *in_attr;
obj_attribute *out_attr;
+ bfd *abi_fp_bfd;
+
+ abi_fp_bfd = mips_elf_tdata (obfd)->abi_fp_bfd;
+ in_attr = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU];
+ if (!abi_fp_bfd && in_attr[Tag_GNU_MIPS_ABI_FP].i != 0)
+ mips_elf_tdata (obfd)->abi_fp_bfd = ibfd;
if (!elf_known_obj_attributes_proc (obfd)[0].i)
{
/* Check for conflicting Tag_GNU_MIPS_ABI_FP attributes and merge
non-conflicting ones. */
- in_attr = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU];
out_attr = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU];
if (in_attr[Tag_GNU_MIPS_ABI_FP].i != out_attr[Tag_GNU_MIPS_ABI_FP].i)
{
out_attr[Tag_GNU_MIPS_ABI_FP].type = 1;
if (out_attr[Tag_GNU_MIPS_ABI_FP].i == 0)
out_attr[Tag_GNU_MIPS_ABI_FP].i = in_attr[Tag_GNU_MIPS_ABI_FP].i;
- else if (in_attr[Tag_GNU_MIPS_ABI_FP].i == 0)
- ;
- else if (in_attr[Tag_GNU_MIPS_ABI_FP].i > 4)
- _bfd_error_handler
- (_("Warning: %B uses unknown floating point ABI %d"), ibfd,
- in_attr[Tag_GNU_MIPS_ABI_FP].i);
- else if (out_attr[Tag_GNU_MIPS_ABI_FP].i > 4)
- _bfd_error_handler
- (_("Warning: %B uses unknown floating point ABI %d"), obfd,
- out_attr[Tag_GNU_MIPS_ABI_FP].i);
- else
+ else if (in_attr[Tag_GNU_MIPS_ABI_FP].i != 0)
switch (out_attr[Tag_GNU_MIPS_ABI_FP].i)
{
case 1:
{
case 2:
_bfd_error_handler
- (_("Warning: %B uses -msingle-float, %B uses -mdouble-float"),
- obfd, ibfd);
+ (_("Warning: %B uses %s (set by %B), %B uses %s"),
+ obfd, abi_fp_bfd, ibfd, "-mdouble-float", "-msingle-float");
break;
case 3:
_bfd_error_handler
- (_("Warning: %B uses hard float, %B uses soft float"),
- obfd, ibfd);
+ (_("Warning: %B uses %s (set by %B), %B uses %s"),
+ obfd, abi_fp_bfd, ibfd, "-mhard-float", "-msoft-float");
break;
case 4:
_bfd_error_handler
- (_("Warning: %B uses -msingle-float, %B uses -mips32r2 -mfp64"),
- obfd, ibfd);
+ (_("Warning: %B uses %s (set by %B), %B uses %s"),
+ obfd, abi_fp_bfd, ibfd,
+ "-mdouble-float", "-mips32r2 -mfp64");
break;
default:
- abort ();
+ _bfd_error_handler
+ (_("Warning: %B uses %s (set by %B), "
+ "%B uses unknown floating point ABI %d"),
+ obfd, abi_fp_bfd, ibfd,
+ "-mdouble-float", in_attr[Tag_GNU_MIPS_ABI_FP].i);
+ break;
}
break;
{
case 1:
_bfd_error_handler
- (_("Warning: %B uses -msingle-float, %B uses -mdouble-float"),
- ibfd, obfd);
+ (_("Warning: %B uses %s (set by %B), %B uses %s"),
+ obfd, abi_fp_bfd, ibfd, "-msingle-float", "-mdouble-float");
break;
case 3:
_bfd_error_handler
- (_("Warning: %B uses hard float, %B uses soft float"),
- obfd, ibfd);
+ (_("Warning: %B uses %s (set by %B), %B uses %s"),
+ obfd, abi_fp_bfd, ibfd, "-mhard-float", "-msoft-float");
break;
case 4:
_bfd_error_handler
- (_("Warning: %B uses -mdouble-float, %B uses -mips32r2 -mfp64"),
- obfd, ibfd);
+ (_("Warning: %B uses %s (set by %B), %B uses %s"),
+ obfd, abi_fp_bfd, ibfd,
+ "-msingle-float", "-mips32r2 -mfp64");
break;
default:
- abort ();
+ _bfd_error_handler
+ (_("Warning: %B uses %s (set by %B), "
+ "%B uses unknown floating point ABI %d"),
+ obfd, abi_fp_bfd, ibfd,
+ "-msingle-float", in_attr[Tag_GNU_MIPS_ABI_FP].i);
+ break;
}
break;
case 2:
case 4:
_bfd_error_handler
- (_("Warning: %B uses hard float, %B uses soft float"),
- ibfd, obfd);
+ (_("Warning: %B uses %s (set by %B), %B uses %s"),
+ obfd, abi_fp_bfd, ibfd, "-msoft-float", "-mhard-float");
break;
default:
- abort ();
+ _bfd_error_handler
+ (_("Warning: %B uses %s (set by %B), "
+ "%B uses unknown floating point ABI %d"),
+ obfd, abi_fp_bfd, ibfd,
+ "-msoft-float", in_attr[Tag_GNU_MIPS_ABI_FP].i);
+ break;
}
break;
{
case 1:
_bfd_error_handler
- (_("Warning: %B uses -msingle-float, %B uses -mips32r2 -mfp64"),
- ibfd, obfd);
+ (_("Warning: %B uses %s (set by %B), %B uses %s"),
+ obfd, abi_fp_bfd, ibfd,
+ "-mips32r2 -mfp64", "-mdouble-float");
break;
case 2:
_bfd_error_handler
- (_("Warning: %B uses -mdouble-float, %B uses -mips32r2 -mfp64"),
- ibfd, obfd);
+ (_("Warning: %B uses %s (set by %B), %B uses %s"),
+ obfd, abi_fp_bfd, ibfd,
+ "-mips32r2 -mfp64", "-msingle-float");
break;
case 3:
_bfd_error_handler
- (_("Warning: %B uses hard float, %B uses soft float"),
- obfd, ibfd);
+ (_("Warning: %B uses %s (set by %B), %B uses %s"),
+ obfd, abi_fp_bfd, ibfd, "-mhard-float", "-msoft-float");
break;
default:
- abort ();
+ _bfd_error_handler
+ (_("Warning: %B uses %s (set by %B), "
+ "%B uses unknown floating point ABI %d"),
+ obfd, abi_fp_bfd, ibfd,
+ "-mips32r2 -mfp64", in_attr[Tag_GNU_MIPS_ABI_FP].i);
+ break;
}
break;
default:
- abort ();
+ switch (in_attr[Tag_GNU_MIPS_ABI_FP].i)
+ {
+ case 1:
+ _bfd_error_handler
+ (_("Warning: %B uses unknown floating point ABI %d "
+ "(set by %B), %B uses %s"),
+ obfd, abi_fp_bfd, ibfd,
+ out_attr[Tag_GNU_MIPS_ABI_FP].i, "-mdouble-float");
+ break;
+
+ case 2:
+ _bfd_error_handler
+ (_("Warning: %B uses unknown floating point ABI %d "
+ "(set by %B), %B uses %s"),
+ obfd, abi_fp_bfd, ibfd,
+ out_attr[Tag_GNU_MIPS_ABI_FP].i, "-msingle-float");
+ break;
+
+ case 3:
+ _bfd_error_handler
+ (_("Warning: %B uses unknown floating point ABI %d "
+ "(set by %B), %B uses %s"),
+ obfd, abi_fp_bfd, ibfd,
+ out_attr[Tag_GNU_MIPS_ABI_FP].i, "-msoft-float");
+ break;
+
+ case 4:
+ _bfd_error_handler
+ (_("Warning: %B uses unknown floating point ABI %d "
+ "(set by %B), %B uses %s"),
+ obfd, abi_fp_bfd, ibfd,
+ out_attr[Tag_GNU_MIPS_ABI_FP].i, "-mips32r2 -mfp64");
+ break;
+
+ default:
+ _bfd_error_handler
+ (_("Warning: %B uses unknown floating point ABI %d "
+ "(set by %B), %B uses unknown floating point ABI %d"),
+ obfd, abi_fp_bfd, ibfd,
+ out_attr[Tag_GNU_MIPS_ABI_FP].i,
+ in_attr[Tag_GNU_MIPS_ABI_FP].i);
+ break;
+ }
+ break;
}
}
if (bfd_get_arch (obfd) == bfd_get_arch (ibfd)
&& (bfd_get_arch_info (obfd)->the_default
- || mips_mach_extends_p (bfd_get_mach (obfd),
+ || mips_mach_extends_p (bfd_get_mach (obfd),
bfd_get_mach (ibfd))))
{
if (! bfd_set_arch_mach (obfd, bfd_get_arch (ibfd),