/* MIPS-specific support for ELF
- Copyright (C) 1993-2016 Free Software Foundation, Inc.
+ Copyright (C) 1993-2018 Free Software Foundation, Inc.
Most of the information added by Ian Lance Taylor, Cygnus Support,
<ian@cygnus.com>.
struct elf_link_hash_entry *low;
/* The least dynamic symbol table index corresponding to a non-TLS
symbol with a GOT entry. */
- long min_got_dynindx;
+ bfd_size_type min_got_dynindx;
/* The greatest dynamic symbol table index corresponding to a symbol
with a GOT entry that is not referenced (e.g., a dynamic symbol
with dynamic relocations pointing to it from non-primary GOTs). */
- long max_unref_got_dynindx;
- /* The greatest dynamic symbol table index not corresponding to a
+ bfd_size_type max_unref_got_dynindx;
+ /* The greatest dynamic symbol table index corresponding to a local
+ symbol. */
+ bfd_size_type max_local_dynindx;
+ /* The greatest dynamic symbol table index corresponding to an external
symbol without a GOT entry. */
- long max_non_got_dynindx;
+ bfd_size_type max_non_got_dynindx;
};
/* We make up to two PLT entries if needed, one for standard MIPS code
/* True if we can only use 32-bit microMIPS instructions. */
bfd_boolean insn32;
+ /* True if we suppress checks for invalid branches between ISA modes. */
+ bfd_boolean ignore_branch_isa;
+
/* True if we're generating code for VxWorks. */
bfd_boolean is_vxworks;
/* True if we already reported the small-data section overflow. */
bfd_boolean small_data_overflow_reported;
+ /* True if we use the special `__gnu_absolute_zero' symbol. */
+ bfd_boolean use_absolute_zero;
+
+ /* True if we have been configured for a GNU target. */
+ bfd_boolean gnu_target;
+
/* Shortcuts to some dynamic sections, or NULL if they are not
being used. */
- asection *srelbss;
- asection *sdynbss;
- asection *srelplt;
asection *srelplt2;
- asection *sgotplt;
- asection *splt;
asection *sstubs;
- asection *sgot;
/* The master GOT information. */
struct mips_got_info *got_info;
/* Put out word-sized data. */
#define MIPS_ELF_PUT_WORD(abfd, val, ptr) \
- (ABI_64_P (abfd) \
- ? bfd_put_64 (abfd, val, ptr) \
+ (ABI_64_P (abfd) \
+ ? bfd_put_64 (abfd, val, ptr) \
: bfd_put_32 (abfd, val, ptr))
/* The opcode for word-sized loads (LW or LD). */
_bfd_elf_add_dynamic_entry (info, tag, val)
#define MIPS_ELF_RTYPE_TO_HOWTO(abfd, rtype, rela) \
- (get_elf_backend_data (abfd)->elf_backend_mips_rtype_to_howto (rtype, rela))
+ (get_elf_backend_data (abfd)->elf_backend_mips_rtype_to_howto (abfd, rtype, rela))
/* The name of the dynamic relocation section. */
#define MIPS_ELF_REL_DYN_NAME(INFO) \
#define STUB_LW(abfd) \
((ABI_64_P (abfd) \
? 0xdf998010 /* ld t9,0x8010(gp) */ \
- : 0x8f998010)) /* lw t9,0x8010(gp) */
+ : 0x8f998010)) /* lw t9,0x8010(gp) */
#define STUB_MOVE 0x03e07825 /* or t7,ra,zero */
#define STUB_LUI(VAL) (0x3c180000 + (VAL)) /* lui t8,VAL */
-#define STUB_JALR 0x0320f809 /* jalr t9,ra */
+#define STUB_JALR 0x0320f809 /* jalr ra,t9 */
#define STUB_ORI(VAL) (0x37180000 + (VAL)) /* ori t8,t8,VAL */
#define STUB_LI16U(VAL) (0x34180000 + (VAL)) /* ori t8,zero,VAL unsigned */
#define STUB_LI16S(abfd, VAL) \
/* The name of the dynamic interpreter. This is put in the .interp
section. */
-#define ELF_DYNAMIC_INTERPRETER(abfd) \
- (ABI_N32_P (abfd) ? "/usr/lib32/libc.so.1" \
- : ABI_64_P (abfd) ? "/usr/lib64/libc.so.1" \
+#define ELF_DYNAMIC_INTERPRETER(abfd) \
+ (ABI_N32_P (abfd) ? "/usr/lib32/libc.so.1" \
+ : ABI_64_P (abfd) ? "/usr/lib64/libc.so.1" \
: "/usr/lib/libc.so.1")
#ifdef BFD64
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);
+ bfd_put_16 (abfd, opcode & 0xffff, ptr + 2);
}
/* microMIPS 32-bit opcode helper retriever. */
const char *prefix, asection *s, bfd_vma value,
bfd_vma size)
{
+ bfd_boolean micromips_p = ELF_ST_IS_MICROMIPS (h->root.other);
struct bfd_link_hash_entry *bh;
struct elf_link_hash_entry *elfh;
char *name;
bfd_boolean res;
- if (ELF_ST_IS_MICROMIPS (h->root.other))
+ if (micromips_p)
value |= 1;
/* Create a new symbol. */
elfh->type = ELF_ST_INFO (STB_LOCAL, STT_FUNC);
elfh->size = size;
elfh->forced_local = 1;
+ if (micromips_p)
+ elfh->other = ELF_ST_SET_MICROMIPS (elfh->other);
return TRUE;
}
&& ! h->need_fn_stub)
{
/* We don't need the fn_stub; the only references to this symbol
- are 16 bit calls. Clobber the size to 0 to prevent it from
- being included in the link. */
+ are 16 bit calls. Clobber the size to 0 to prevent it from
+ being included in the link. */
h->fn_stub->size = 0;
h->fn_stub->flags &= ~SEC_RELOC;
h->fn_stub->reloc_count = 0;
&& ELF_ST_IS_MIPS16 (h->root.other))
{
/* We don't need the call_stub; this is a 16 bit function, so
- calls from other 16 bit functions are OK. Clobber the size
- to 0 to prevent it from being included in the link. */
+ calls from other 16 bit functions are OK. Clobber the size
+ to 0 to prevent it from being included in the link. */
h->call_stub->size = 0;
h->call_stub->flags &= ~SEC_RELOC;
h->call_stub->reloc_count = 0;
&& ELF_ST_IS_MIPS16 (h->root.other))
{
/* We don't need the call_stub; this is a 16 bit function, so
- calls from other 16 bit functions are OK. Clobber the size
- to 0 to prevent it from being included in the link. */
+ calls from other 16 bit functions are OK. Clobber the size
+ to 0 to prevent it from being included in the link. */
h->call_fp_stub->size = 0;
h->call_fp_stub->flags &= ~SEC_RELOC;
h->call_fp_stub->reloc_count = 0;
|| h->root.root.type == bfd_link_hash_defweak)
&& h->root.def_regular
&& !bfd_is_abs_section (h->root.root.u.def.section)
+ && !bfd_is_und_section (h->root.root.u.def.section)
&& (!ELF_ST_IS_MIPS16 (h->root.other)
|| (h->fn_stub && h->need_fn_stub))
&& (PIC_OBJECT_P (h->root.root.u.def.section->owner)
/* Prefer to use LUI/ADDIU stubs if the function is at the beginning
of the section and if we would need no more than 2 nops. */
value = mips_elf_get_la25_target (stub, &s);
+ if (ELF_ST_IS_MICROMIPS (stub->h->root.other))
+ value &= ~1;
use_trampoline_p = (value != 0 || s->alignment_power > 4);
h->la25_stub = stub;
+--------------+--------------------------------+
| JALX | X| Imm 20:16 | Imm 25:21 |
+--------------+--------------------------------+
- | Immediate 15:0 |
+ | Immediate 15:0 |
+-----------------------------------------------+
JALX is the 5-bit value 00011. X is 0 for jal, 1 for jalx.
big-endian:
+--------+----------------------+
- | | |
- | | targ26-16 |
- |31 26|25 0|
+ | | |
+ | | targ26-16 |
+ |31 26|25 0|
+--------+----------------------+
little-endian:
+----------+------+-------------+
- | | | |
- | sub1 | | sub2 |
- |0 9|10 15|16 31|
+ | | | |
+ | sub1 | | sub2 |
+ |0 9|10 15|16 31|
+----------+--------------------+
where targ26-16 is sub1 followed by sub2 (i.e., the addend field A is
((sub1 << 16) | sub2)).
All we need to do here is shuffle the bits appropriately.
As above, the two 16-bit halves must be swapped on a
- little-endian system. */
+ little-endian system.
+
+ Finally R_MIPS16_PC16_S1 corresponds to R_MIPS_PC16, however the
+ relocatable field is shifted by 1 rather than 2 and the same bit
+ shuffling is done as with the relocations above. */
static inline bfd_boolean
mips16_reloc_p (int r_type)
case R_MIPS16_TLS_GOTTPREL:
case R_MIPS16_TLS_TPREL_HI16:
case R_MIPS16_TLS_TPREL_LO16:
+ case R_MIPS16_PC16_S1:
return TRUE;
default:
|| r_type == R_MICROMIPS_26_S1);
}
+static inline bfd_boolean
+b_reloc_p (int r_type)
+{
+ return (r_type == R_MIPS_PC26_S2
+ || r_type == R_MIPS_PC21_S2
+ || r_type == R_MIPS_PC16
+ || r_type == R_MIPS_GNU_REL16_S2
+ || r_type == R_MIPS16_PC16_S1
+ || r_type == R_MICROMIPS_PC16_S1
+ || r_type == R_MICROMIPS_PC10_S1
+ || r_type == R_MICROMIPS_PC7_S1);
+}
+
static inline bfd_boolean
aligned_pcrel_reloc_p (int r_type)
{
|| r_type == R_MIPS_PC19_S2);
}
+static inline bfd_boolean
+branch_reloc_p (int r_type)
+{
+ return (r_type == R_MIPS_26
+ || r_type == R_MIPS_PC26_S2
+ || r_type == R_MIPS_PC21_S2
+ || r_type == R_MIPS_PC16
+ || r_type == R_MIPS_GNU_REL16_S2);
+}
+
+static inline bfd_boolean
+mips16_branch_reloc_p (int r_type)
+{
+ return (r_type == R_MIPS16_26
+ || r_type == R_MIPS16_PC16_S1);
+}
+
static inline bfd_boolean
micromips_branch_reloc_p (int r_type)
{
const char *name;
/* Use undefined class. Also, set class and type for some
- special symbols. */
+ special symbols. */
name = h->root.root.root.string;
if (strcmp (name, mips_elf_dynsym_rtproc_names[0]) == 0
|| strcmp (name, mips_elf_dynsym_rtproc_names[1]) == 0)
h->esym.asym.value =
mips_elf_hash_table (einfo->info)->procedure_count;
}
- else if (strcmp (name, "_gp_disp") == 0 && ! NEWABI_P (einfo->abfd))
- {
- h->esym.asym.sc = scAbs;
- h->esym.asym.st = stLabel;
- h->esym.asym.value = elf_gp (einfo->abfd);
- }
else
h->esym.asym.sc = scUndefined;
}
bfd_boolean need_relocs = FALSE;
bfd_boolean dyn = elf_hash_table (info)->dynamic_sections_created;
- if (h && WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h)
- && (!bfd_link_pic (info) || !SYMBOL_REFERENCES_LOCAL (info, h)))
+ if (h != NULL
+ && h->dynindx != -1
+ && WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h)
+ && (bfd_link_dll (info) || !SYMBOL_REFERENCES_LOCAL (info, h)))
indx = h->dynindx;
- if ((bfd_link_pic (info) || indx != 0)
+ if ((bfd_link_dll (info) || indx != 0)
&& (h == NULL
|| ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
|| h->root.type != bfd_link_hash_undefweak))
return 1;
case GOT_TLS_LDM:
- return bfd_link_pic (info) ? 1 : 0;
+ return bfd_link_dll (info) ? 1 : 0;
default:
return 0;
struct mips_elf_link_hash_entry *h,
bfd_vma value)
{
+ bfd_boolean dyn = elf_hash_table (info)->dynamic_sections_created;
struct mips_elf_link_hash_table *htab;
int indx;
asection *sreloc, *sgot;
if (htab == NULL)
return;
- sgot = htab->sgot;
+ sgot = htab->root.sgot;
indx = 0;
- if (h != NULL)
- {
- bfd_boolean dyn = elf_hash_table (info)->dynamic_sections_created;
-
- if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info),
- &h->root)
- && (!bfd_link_pic (info)
- || !SYMBOL_REFERENCES_LOCAL (info, &h->root)))
- indx = h->root.dynindx;
- }
+ if (h != NULL
+ && h->root.dynindx != -1
+ && WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), &h->root)
+ && (bfd_link_dll (info) || !SYMBOL_REFERENCES_LOCAL (info, &h->root)))
+ indx = h->root.dynindx;
if (entry->tls_initialized)
return;
- if ((bfd_link_pic (info) || indx != 0)
+ if ((bfd_link_dll (info) || indx != 0)
&& (h == NULL
|| ELF_ST_VISIBILITY (h->root.other) == STV_DEFAULT
|| h->root.type != bfd_link_hash_undefweak))
sgot->contents + got_offset
+ MIPS_ELF_GOT_SIZE (abfd));
- if (!bfd_link_pic (info))
+ if (!bfd_link_dll (info))
MIPS_ELF_PUT_WORD (abfd, 1,
sgot->contents + got_offset);
else
BFD_ASSERT (h->plt.plist->gotplt_index != MINUS_ONE);
/* Calculate the address of the associated .got.plt entry. */
- got_address = (htab->sgotplt->output_section->vma
- + htab->sgotplt->output_offset
+ got_address = (htab->root.sgotplt->output_section->vma
+ + htab->root.sgotplt->output_offset
+ (h->plt.plist->gotplt_index
* MIPS_ELF_GOT_SIZE (info->output_bfd)));
g = mips_elf_bfd_got (obfd, FALSE);
got_index = ((h->dynindx - global_got_dynindx + g->local_gotno)
* MIPS_ELF_GOT_SIZE (obfd));
- BFD_ASSERT (got_index < htab->sgot->size);
+ BFD_ASSERT (got_index < htab->root.sgot->size);
return got_index;
}
BFD_ASSERT (entry);
gotidx = entry->gotidx;
- BFD_ASSERT (gotidx > 0 && gotidx < htab->sgot->size);
+ BFD_ASSERT (gotidx > 0 && gotidx < htab->root.sgot->size);
if (lookup.tls_type)
{
htab = mips_elf_hash_table (info);
BFD_ASSERT (htab != NULL);
- sgot = htab->sgot;
+ sgot = htab->root.sgot;
gp = _bfd_get_gp_value (output_bfd)
+ mips_elf_adjust_gp (output_bfd, htab->got_info, input_bfd);
BFD_ASSERT (entry);
gotidx = entry->gotidx;
- BFD_ASSERT (gotidx > 0 && gotidx < htab->sgot->size);
+ BFD_ASSERT (gotidx > 0 && gotidx < htab->root.sgot->size);
return entry;
}
if (g->assigned_low_gotno > g->assigned_high_gotno)
{
/* We didn't allocate enough space in the GOT. */
- (*_bfd_error_handler)
+ _bfd_error_handler
(_("not enough GOT space for local GOT entries"));
bfd_set_error (bfd_error_bad_value);
return NULL;
*entry = lookup;
*loc = entry;
- MIPS_ELF_PUT_WORD (abfd, value, htab->sgot->contents + entry->gotidx);
+ MIPS_ELF_PUT_WORD (abfd, value, htab->root.sgot->contents + entry->gotidx);
/* These GOT entries need a dynamic relocation on VxWorks. */
if (htab->is_vxworks)
bfd_vma got_address;
s = mips_elf_rel_dyn_section (info, FALSE);
- got_address = (htab->sgot->output_section->vma
- + htab->sgot->output_offset
+ got_address = (htab->root.sgot->output_section->vma
+ + htab->root.sgot->output_offset
+ entry->gotidx);
rloc = s->contents + (s->reloc_count++ * sizeof (Elf32_External_Rela));
for (p = output_bfd->sections; p ; p = p->next)
if ((p->flags & SEC_EXCLUDE) == 0
&& (p->flags & SEC_ALLOC) != 0
+ && elf_hash_table (info)->dynamic_relocs
&& !(*bed->elf_backend_omit_section_dynsym) (output_bfd, info, p))
++count;
}
struct mips_elf_hash_sort_data hsd;
struct mips_got_info *g;
- if (elf_hash_table (info)->dynsymcount == 0)
- return TRUE;
-
htab = mips_elf_hash_table (info);
BFD_ASSERT (htab != NULL);
+ if (htab->root.dynsymcount == 0)
+ return TRUE;
+
g = htab->got_info;
if (g == NULL)
return TRUE;
hsd.low = NULL;
hsd.max_unref_got_dynindx
= hsd.min_got_dynindx
- = (elf_hash_table (info)->dynsymcount - g->reloc_only_gotno);
- hsd.max_non_got_dynindx = count_section_dynsyms (abfd, info) + 1;
- mips_elf_link_hash_traverse (((struct mips_elf_link_hash_table *)
- elf_hash_table (info)),
- mips_elf_sort_hash_table_f,
- &hsd);
+ = (htab->root.dynsymcount - g->reloc_only_gotno);
+ /* Add 1 to local symbol indices to account for the mandatory NULL entry
+ at the head of the table; see `_bfd_elf_link_renumber_dynsyms'. */
+ hsd.max_local_dynindx = count_section_dynsyms (abfd, info) + 1;
+ hsd.max_non_got_dynindx = htab->root.local_dynsymcount + 1;
+ mips_elf_link_hash_traverse (htab, mips_elf_sort_hash_table_f, &hsd);
/* There should have been enough room in the symbol table to
accommodate both the GOT and non-GOT symbols. */
+ BFD_ASSERT (hsd.max_local_dynindx <= htab->root.local_dynsymcount + 1);
BFD_ASSERT (hsd.max_non_got_dynindx <= hsd.min_got_dynindx);
- BFD_ASSERT ((unsigned long) hsd.max_unref_got_dynindx
- == elf_hash_table (info)->dynsymcount);
- BFD_ASSERT (elf_hash_table (info)->dynsymcount - hsd.min_got_dynindx
- == g->global_gotno);
+ BFD_ASSERT (hsd.max_unref_got_dynindx == htab->root.dynsymcount);
+ BFD_ASSERT (htab->root.dynsymcount - hsd.min_got_dynindx == g->global_gotno);
/* Now we know which dynamic symbol has the lowest dynamic symbol
table index in the GOT. */
switch (h->global_got_area)
{
case GGA_NONE:
- h->root.dynindx = hsd->max_non_got_dynindx++;
+ if (h->root.forced_local)
+ h->root.dynindx = hsd->max_local_dynindx++;
+ else
+ h->root.dynindx = hsd->max_non_got_dynindx++;
break;
case GGA_NORMAL:
{
case STV_INTERNAL:
case STV_HIDDEN:
- _bfd_elf_link_hash_hide_symbol (info, h, TRUE);
+ _bfd_mips_elf_hide_symbol (info, h, TRUE);
break;
}
if (!bfd_elf_link_record_dynamic_symbol (info, h))
if (h->root.dynindx == -1)
return TRUE;
+ /* Absolute symbols, if ever they need a GOT entry, cannot ever go
+ to the local GOT, as they would be implicitly relocated by the
+ base address by the dynamic loader. */
+ if (bfd_is_abs_symbol (&h->root.root))
+ return FALSE;
+
/* Symbols that bind locally can (and in the case of forced-local
symbols, must) live in the local GOT. */
if (h->got_only_for_calls
BFD_ASSERT (htab != NULL);
/* This function may be called more than once. */
- if (htab->sgot)
+ if (htab->root.sgot)
return TRUE;
flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
if (s == NULL
|| ! bfd_set_section_alignment (abfd, s, 4))
return FALSE;
- htab->sgot = s;
+ htab->root.sgot = s;
/* Define the symbol _GLOBAL_OFFSET_TABLE_. We don't do this in the
linker script because we don't want to define the symbol if we
| SEC_LINKER_CREATED);
if (s == NULL)
return FALSE;
- htab->sgotplt = s;
+ htab->root.sgotplt = s;
return TRUE;
}
}
}
\f
+/* Obtain the field relocated by RELOCATION. */
+
+static bfd_vma
+mips_elf_obtain_contents (reloc_howto_type *howto,
+ const Elf_Internal_Rela *relocation,
+ bfd *input_bfd, bfd_byte *contents)
+{
+ bfd_vma x = 0;
+ bfd_byte *location = contents + relocation->r_offset;
+ unsigned int size = bfd_get_reloc_size (howto);
+
+ /* Obtain the bytes. */
+ if (size != 0)
+ x = bfd_get (8 * size, input_bfd, location);
+
+ return x;
+}
+
+/* Store the field relocated by RELOCATION. */
+
+static void
+mips_elf_store_contents (reloc_howto_type *howto,
+ const Elf_Internal_Rela *relocation,
+ bfd *input_bfd, bfd_byte *contents, bfd_vma x)
+{
+ bfd_byte *location = contents + relocation->r_offset;
+ unsigned int size = bfd_get_reloc_size (howto);
+
+ /* Put the value into the output. */
+ if (size != 0)
+ bfd_put (8 * size, input_bfd, x, location);
+}
+
+/* Try to patch a load from GOT instruction in CONTENTS pointed to by
+ RELOCATION described by HOWTO, with a move of 0 to the load target
+ register, returning TRUE if that is successful and FALSE otherwise.
+ If DOIT is FALSE, then only determine it patching is possible and
+ return status without actually changing CONTENTS.
+*/
+
+static bfd_boolean
+mips_elf_nullify_got_load (bfd *input_bfd, bfd_byte *contents,
+ const Elf_Internal_Rela *relocation,
+ reloc_howto_type *howto, bfd_boolean doit)
+{
+ int r_type = ELF_R_TYPE (input_bfd, relocation->r_info);
+ bfd_byte *location = contents + relocation->r_offset;
+ bfd_boolean nullified = TRUE;
+ bfd_vma x;
+
+ _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);
+
+ /* Note that in the unshuffled MIPS16 encoding RX is at bits [21:19]
+ while RY is at bits [18:16] of the combined 32-bit instruction word. */
+ if (mips16_reloc_p (r_type)
+ && (((x >> 22) & 0x3ff) == 0x3d3 /* LW */
+ || ((x >> 22) & 0x3ff) == 0x3c7)) /* LD */
+ x = (0x3cd << 22) | (x & (7 << 16)) << 3; /* LI */
+ else if (micromips_reloc_p (r_type)
+ && ((x >> 26) & 0x37) == 0x37) /* LW/LD */
+ x = (0xc << 26) | (x & (0x1f << 21)); /* ADDIU */
+ else if (((x >> 26) & 0x3f) == 0x23 /* LW */
+ || ((x >> 26) & 0x3f) == 0x37) /* LD */
+ x = (0x9 << 26) | (x & (0x1f << 16)); /* ADDIU */
+ else
+ nullified = FALSE;
+
+ /* Put the value into the output. */
+ if (doit && nullified)
+ mips_elf_store_contents (howto, relocation, input_bfd, contents, x);
+
+ _bfd_mips_elf_reloc_shuffle (input_bfd, r_type, FALSE, location);
+
+ return nullified;
+}
+
/* Calculate the value produced by the RELOCATION (which comes from
the INPUT_BFD). The ADDEND is the addend to use for this
RELOCATION; RELOCATION->R_ADDEND is ignored.
static bfd_reloc_status_type
mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
- asection *input_section,
+ asection *input_section, bfd_byte *contents,
struct bfd_link_info *info,
const Elf_Internal_Rela *relocation,
bfd_vma addend, reloc_howto_type *howto,
/* TRUE if the symbol referred to by this relocation is a local
symbol. */
bfd_boolean local_p, was_local_p;
+ /* TRUE if the symbol referred to by this relocation is a section
+ symbol. */
+ bfd_boolean section_p = FALSE;
/* TRUE if the symbol referred to by this relocation is "_gp_disp". */
bfd_boolean gp_disp_p = FALSE;
/* TRUE if the symbol referred to by this relocation is
bfd_boolean target_is_micromips_code_p = FALSE;
struct mips_elf_link_hash_table *htab;
bfd *dynobj;
+ bfd_boolean resolved_to_zero;
dynobj = elf_hash_table (info)->dynobj;
htab = mips_elf_hash_table (info);
/* Figure out the value of the symbol. */
if (local_p)
{
+ bfd_boolean micromips_p = MICROMIPS_P (abfd);
Elf_Internal_Sym *sym;
sym = local_syms + r_symndx;
sec = local_sections[r_symndx];
+ section_p = ELF_ST_TYPE (sym->st_info) == STT_SECTION;
+
symbol = sec->output_section->vma + sec->output_offset;
- if (ELF_ST_TYPE (sym->st_info) != STT_SECTION
- || (sec->flags & SEC_MERGE))
+ if (!section_p || (sec->flags & SEC_MERGE))
symbol += sym->st_value;
- if ((sec->flags & SEC_MERGE)
- && ELF_ST_TYPE (sym->st_info) == STT_SECTION)
+ if ((sec->flags & SEC_MERGE) && section_p)
{
addend = _bfd_elf_rel_local_sym (abfd, sym, &sec, addend);
addend -= symbol;
if (*namep == NULL || **namep == '\0')
*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);
+ /* For relocations against a section symbol and ones against no
+ symbol (absolute relocations) infer the ISA mode from the addend. */
+ if (section_p || r_symndx == STN_UNDEF)
+ {
+ target_is_16_bit_code_p = (addend & 1) && !micromips_p;
+ target_is_micromips_code_p = (addend & 1) && micromips_p;
+ }
+ /* For relocations against an absolute symbol infer the ISA mode
+ from the value of the symbol plus addend. */
+ else if (bfd_is_abs_section (sec))
+ {
+ target_is_16_bit_code_p = ((symbol + addend) & 1) && !micromips_p;
+ target_is_micromips_code_p = ((symbol + addend) & 1) && micromips_p;
+ }
+ /* Otherwise just use the regular symbol annotation available. */
+ else
+ {
+ 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
{
{
/* If this is a dynamic link, we should have created a
_DYNAMIC_LINK symbol or _DYNAMIC_LINKING(for normal mips) symbol
- in in _bfd_mips_elf_create_dynamic_sections.
+ in _bfd_mips_elf_create_dynamic_sections.
Otherwise, we should define the symbol with a value of 0.
FIXME: It should probably get into the symbol table
somehow as well. */
http://techpubs.sgi.com/library/manuals/4000/007-4658-001/pdf/007-4658-001.pdf */
symbol = 0;
}
- else if ((*info->callbacks->undefined_symbol)
- (info, h->root.root.root.string, input_bfd,
- input_section, relocation->r_offset,
- (info->unresolved_syms_in_objects == RM_GENERATE_ERROR)
- || ELF_ST_VISIBILITY (h->root.other)))
- {
- return bfd_reloc_undefined;
- }
else
{
- return bfd_reloc_notsupported;
+ bfd_boolean reject_undefined
+ = (info->unresolved_syms_in_objects == RM_GENERATE_ERROR
+ || ELF_ST_VISIBILITY (h->root.other) != STV_DEFAULT);
+
+ (*info->callbacks->undefined_symbol)
+ (info, h->root.root.root.string, input_bfd,
+ input_section, relocation->r_offset, reject_undefined);
+
+ if (reject_undefined)
+ return bfd_reloc_undefined;
+
+ symbol = 0;
}
target_is_16_bit_code_p = ELF_ST_IS_MIPS16 (h->root.other);
sec = h->call_stub;
else
sec = h->call_fp_stub;
- }
+ }
BFD_ASSERT (sec->size > 0);
symbol = sec->output_section->vma + sec->output_offset;
else if (h != NULL && h->la25_stub
&& 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);
+ {
+ symbol = (h->la25_stub->stub_section->output_section->vma
+ + h->la25_stub->stub_section->output_offset
+ + h->la25_stub->offset);
+ if (ELF_ST_IS_MICROMIPS (h->root.other))
+ symbol |= 1;
+ }
/* For direct MIPS16 and microMIPS calls make sure the compressed PLT
entry is used if a standard PLT entry has also been made. In this
case the symbol will have been set by mips_elf_set_plt_sym_value
to point to the standard PLT entry, so redirect to the compressed
one. */
- else if ((r_type == R_MIPS16_26 || r_type == R_MICROMIPS_26_S1)
+ else if ((mips16_branch_reloc_p (r_type)
+ || micromips_branch_reloc_p (r_type))
&& !bfd_link_relocatable (info)
&& h != NULL
&& h->use_plt_entry
{
bfd_boolean micromips_p = MICROMIPS_P (abfd);
- sec = htab->splt;
+ sec = htab->root.splt;
symbol = (sec->output_section->vma
+ sec->output_offset
+ htab->plt_header_size
}
/* Make sure MIPS16 and microMIPS are not used together. */
- if ((r_type == R_MIPS16_26 && target_is_micromips_code_p)
+ if ((mips16_branch_reloc_p (r_type) && target_is_micromips_code_p)
|| (micromips_branch_reloc_p (r_type) && target_is_16_bit_code_p))
{
- (*_bfd_error_handler)
+ _bfd_error_handler
(_("MIPS16 and microMIPS functions cannot call each other"));
return bfd_reloc_notsupported;
}
acceptable. */
*cross_mode_jump_p = (!bfd_link_relocatable (info)
&& !(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
+ && ((mips16_branch_reloc_p (r_type)
+ && !target_is_16_bit_code_p)
+ || (micromips_branch_reloc_p (r_type)
&& !target_is_micromips_code_p)
- || ((r_type == R_MIPS_26 || r_type == R_MIPS_JALR)
+ || ((branch_reloc_p (r_type)
+ || r_type == R_MIPS_JALR)
&& (target_is_16_bit_code_p
|| target_is_micromips_code_p))));
+ resolved_to_zero = (h != NULL
+ && UNDEFWEAK_NO_DYNAMIC_RELOC (info, &h->root));
+
+ switch (r_type)
+ {
+ case R_MIPS16_CALL16:
+ case R_MIPS16_GOT16:
+ case R_MIPS_CALL16:
+ case R_MIPS_GOT16:
+ case R_MIPS_GOT_PAGE:
+ case R_MIPS_GOT_DISP:
+ case R_MIPS_GOT_LO16:
+ case R_MIPS_CALL_LO16:
+ case R_MICROMIPS_CALL16:
+ case R_MICROMIPS_GOT16:
+ case R_MICROMIPS_GOT_PAGE:
+ case R_MICROMIPS_GOT_DISP:
+ case R_MICROMIPS_GOT_LO16:
+ case R_MICROMIPS_CALL_LO16:
+ if (resolved_to_zero
+ && !bfd_link_relocatable (info)
+ && mips_elf_nullify_got_load (input_bfd, contents,
+ relocation, howto, TRUE))
+ return bfd_reloc_continue;
+
+ /* Fall through. */
+ case R_MIPS_GOT_HI16:
+ case R_MIPS_CALL_HI16:
+ case R_MICROMIPS_GOT_HI16:
+ case R_MICROMIPS_CALL_HI16:
+ if (resolved_to_zero
+ && htab->use_absolute_zero
+ && bfd_link_pic (info))
+ {
+ /* Redirect to the special `__gnu_absolute_zero' symbol. */
+ h = mips_elf_link_hash_lookup (htab, "__gnu_absolute_zero",
+ FALSE, FALSE, FALSE);
+ BFD_ASSERT (h != NULL);
+ }
+ break;
+ }
+
local_p = (h == NULL || mips_use_local_got_p (info, h));
gp0 = _bfd_get_gp_value (input_bfd);
if (!TLS_RELOC_P (r_type)
&& !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);
+ MIPS_ELF_PUT_WORD (dynobj, symbol, htab->root.sgot->contents + g);
}
}
else if (!htab->is_vxworks
&& r_symndx != STN_UNDEF
&& (h == NULL
|| h->root.root.type != bfd_link_hash_undefweak
- || ELF_ST_VISIBILITY (h->root.other) == STV_DEFAULT)
+ || (ELF_ST_VISIBILITY (h->root.other) == STV_DEFAULT
+ && !resolved_to_zero))
&& (input_section->flags & SEC_ALLOC) != 0)
{
/* If we're creating a shared library, then we can't know
/* 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 if (howto->partial_inplace)
+ if (howto->partial_inplace && !section_p)
value = _bfd_mips_elf_sign_extend (addend, 26 + shift);
else
value = addend;
value += symbol;
- /* 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 && (value & 3) != (r_type == R_MIPS_26))
+ /* Make sure the target of a jump is suitably aligned. Bit 0 must
+ be the correct ISA mode selector except for weak undefined
+ symbols. */
+ if ((was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+ && (*cross_mode_jump_p
+ ? (value & 3) != (r_type == R_MIPS_26)
+ : (value & ((1 << shift) - 1)) != (r_type != R_MIPS_26)))
return bfd_reloc_outofrange;
value >>= shift;
- if (!was_local_p && h->root.root.type != bfd_link_hash_undefweak)
+ if (was_local_p || h->root.root.type != bfd_link_hash_undefweak)
overflowed_p = (value >> 26) != ((p + 4) >> (26 + shift));
value &= howto->dst_mask;
}
else
{
/* For MIPS16 ABI code we generate this sequence
- 0: li $v0,%hi(_gp_disp)
- 4: addiupc $v1,%lo(_gp_disp)
- 8: sll $v0,16
+ 0: li $v0,%hi(_gp_disp)
+ 4: addiupc $v1,%lo(_gp_disp)
+ 8: sll $v0,16
12: addu $v0,$v1
14: move $gp,$v0
So the offsets of hi and lo relocs are the same, but the
value = mips_elf_high (addend + gp - p - 1);
else
value = mips_elf_high (addend + gp - p);
- overflowed_p = mips_elf_overflow_p (value, 16);
}
break;
if (howto->partial_inplace)
addend = _bfd_mips_elf_sign_extend (addend, 18);
- if ((symbol + addend) & 3)
+ /* No need to exclude weak undefined symbols here as they resolve
+ to 0 and never set `*cross_mode_jump_p', so this alignment check
+ will never trigger for them. */
+ if (*cross_mode_jump_p
+ ? ((symbol + addend) & 3) != 1
+ : ((symbol + addend) & 3) != 0)
return bfd_reloc_outofrange;
value = symbol + addend - p;
value &= howto->dst_mask;
break;
+ case R_MIPS16_PC16_S1:
+ if (howto->partial_inplace)
+ addend = _bfd_mips_elf_sign_extend (addend, 17);
+
+ if ((was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+ && (*cross_mode_jump_p
+ ? ((symbol + addend) & 3) != 0
+ : ((symbol + addend) & 1) == 0))
+ return bfd_reloc_outofrange;
+
+ value = symbol + addend - p;
+ if (was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+ overflowed_p = mips_elf_overflow_p (value, 17);
+ value >>= howto->rightshift;
+ value &= howto->dst_mask;
+ break;
+
case R_MIPS_PC21_S2:
if (howto->partial_inplace)
addend = _bfd_mips_elf_sign_extend (addend, 23);
case R_MICROMIPS_PC7_S1:
if (howto->partial_inplace)
addend = _bfd_mips_elf_sign_extend (addend, 8);
+
+ if ((was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+ && (*cross_mode_jump_p
+ ? ((symbol + addend + 2) & 3) != 0
+ : ((symbol + addend + 2) & 1) == 0))
+ return bfd_reloc_outofrange;
+
value = symbol + addend - p;
if (was_local_p || h->root.root.type != bfd_link_hash_undefweak)
overflowed_p = mips_elf_overflow_p (value, 8);
case R_MICROMIPS_PC10_S1:
if (howto->partial_inplace)
addend = _bfd_mips_elf_sign_extend (addend, 11);
+
+ if ((was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+ && (*cross_mode_jump_p
+ ? ((symbol + addend + 2) & 3) != 0
+ : ((symbol + addend + 2) & 1) == 0))
+ return bfd_reloc_outofrange;
+
value = symbol + addend - p;
if (was_local_p || h->root.root.type != bfd_link_hash_undefweak)
overflowed_p = mips_elf_overflow_p (value, 11);
case R_MICROMIPS_PC16_S1:
if (howto->partial_inplace)
addend = _bfd_mips_elf_sign_extend (addend, 17);
+
+ if ((was_local_p || h->root.root.type != bfd_link_hash_undefweak)
+ && (*cross_mode_jump_p
+ ? ((symbol + addend) & 3) != 0
+ : ((symbol + addend) & 1) == 0))
+ return bfd_reloc_outofrange;
+
value = symbol + addend - p;
if (was_local_p || h->root.root.type != bfd_link_hash_undefweak)
overflowed_p = mips_elf_overflow_p (value, 17);
when the symbol does not resolve locally. */
if (h != NULL && !SYMBOL_CALLS_LOCAL (info, &h->root))
return bfd_reloc_continue;
+ /* We can't optimize cross-mode jumps either. */
+ if (*cross_mode_jump_p)
+ return bfd_reloc_continue;
value = symbol + addend;
+ /* Neither we can non-instruction-aligned targets. */
+ if (r_type == R_MIPS_JALR ? (value & 3) != 0 : (value & 1) == 0)
+ return bfd_reloc_continue;
break;
case R_MIPS_PJUMP:
return overflowed_p ? bfd_reloc_overflow : bfd_reloc_ok;
}
-/* Obtain the field relocated by RELOCATION. */
-
-static bfd_vma
-mips_elf_obtain_contents (reloc_howto_type *howto,
- const Elf_Internal_Rela *relocation,
- bfd *input_bfd, bfd_byte *contents)
-{
- bfd_vma x = 0;
- bfd_byte *location = contents + relocation->r_offset;
- unsigned int size = bfd_get_reloc_size (howto);
-
- /* Obtain the bytes. */
- if (size != 0)
- x = bfd_get (8 * size, input_bfd, location);
-
- return x;
-}
-
/* 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
bfd_vma x;
bfd_byte *location;
int r_type = ELF_R_TYPE (input_bfd, relocation->r_info);
- unsigned int size;
/* Figure out where the relocation is occurring. */
location = contents + relocation->r_offset;
/* Set the field. */
x |= (value & howto->dst_mask);
- /* If required, turn JAL into JALX. */
+ /* Detect incorrect JALX usage. If required, turn JAL or BAL into JALX. */
+ if (!cross_mode_jump_p && jal_reloc_p (r_type))
+ {
+ bfd_vma opcode = x >> 26;
+
+ if (r_type == R_MIPS16_26 ? opcode == 0x7
+ : r_type == R_MICROMIPS_26_S1 ? opcode == 0x3c
+ : opcode == 0x1d)
+ {
+ info->callbacks->einfo
+ (_("%X%H: unsupported JALX to the same ISA mode\n"),
+ input_bfd, input_section, relocation->r_offset);
+ return TRUE;
+ }
+ }
if (cross_mode_jump_p && jal_reloc_p (r_type))
{
bfd_boolean ok;
}
/* If the opcode is not JAL or JALX, there's a problem. We cannot
- convert J or JALS to JALX. */
+ convert J or JALS to JALX. */
if (!ok)
{
- (*_bfd_error_handler)
- (_("%B: %A+0x%lx: Unsupported jump between ISA modes; consider recompiling with interlinking enabled."),
- input_bfd,
- input_section,
- (unsigned long) relocation->r_offset);
- bfd_set_error (bfd_error_bad_value);
- return FALSE;
+ info->callbacks->einfo
+ (_("%X%H: unsupported jump between ISA modes; "
+ "consider recompiling with interlinking enabled\n"),
+ input_bfd, input_section, relocation->r_offset);
+ return TRUE;
}
/* Make this the JALX opcode. */
x = (x & ~(0x3f << 26)) | (jalx_opcode << 26);
}
+ else if (cross_mode_jump_p && b_reloc_p (r_type))
+ {
+ bfd_boolean ok = FALSE;
+ bfd_vma opcode = x >> 16;
+ bfd_vma jalx_opcode = 0;
+ bfd_vma sign_bit = 0;
+ bfd_vma addr;
+ bfd_vma dest;
+
+ if (r_type == R_MICROMIPS_PC16_S1)
+ {
+ ok = opcode == 0x4060;
+ jalx_opcode = 0x3c;
+ sign_bit = 0x10000;
+ value <<= 1;
+ }
+ else if (r_type == R_MIPS_PC16 || r_type == R_MIPS_GNU_REL16_S2)
+ {
+ ok = opcode == 0x411;
+ jalx_opcode = 0x1d;
+ sign_bit = 0x20000;
+ value <<= 2;
+ }
+
+ if (ok && !bfd_link_pic (info))
+ {
+ addr = (input_section->output_section->vma
+ + input_section->output_offset
+ + relocation->r_offset
+ + 4);
+ dest = (addr
+ + (((value & ((sign_bit << 1) - 1)) ^ sign_bit) - sign_bit));
+
+ if ((addr >> 28) << 28 != (dest >> 28) << 28)
+ {
+ info->callbacks->einfo
+ (_("%X%H: cannot convert branch between ISA modes "
+ "to JALX: relocation out of range\n"),
+ input_bfd, input_section, relocation->r_offset);
+ return TRUE;
+ }
+
+ /* Make this the JALX opcode. */
+ x = ((dest >> 2) & 0x3ffffff) | jalx_opcode << 26;
+ }
+ else if (!mips_elf_hash_table (info)->ignore_branch_isa)
+ {
+ info->callbacks->einfo
+ (_("%X%H: unsupported branch between ISA modes\n"),
+ input_bfd, input_section, relocation->r_offset);
+ return TRUE;
+ }
+ }
/* Try converting JAL to BAL and J(AL)R to B(AL), if the target is in
range. */
&& !cross_mode_jump_p
&& ((JAL_TO_BAL_P (input_bfd)
&& r_type == R_MIPS_26
- && (x >> 26) == 0x3) /* jal addr */
+ && (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 */
+ && (x & ~1) == 0x03200008))) /* jr t9 / jalr zero, t9 */
{
bfd_vma addr;
bfd_vma dest;
off = dest - addr;
if (off <= 0x1ffff && off >= -0x20000)
{
- if (x == 0x03200008) /* jr t9 */
+ if ((x & ~1) == 0x03200008) /* jr t9 / jalr zero, 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. */
- size = bfd_get_reloc_size (howto);
- if (size != 0)
- bfd_put (8 * size, input_bfd, x, location);
+ mips_elf_store_contents (howto, relocation, input_bfd, contents, x);
_bfd_mips_elf_reloc_shuffle (input_bfd, r_type, !bfd_link_relocatable (info),
location);
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_GS464:
+ return bfd_mach_mips_gs464;
+
+ case E_MIPS_MACH_GS464E:
+ return bfd_mach_mips_gs464e;
+
+ case E_MIPS_MACH_GS264E:
+ return bfd_mach_mips_gs264e;
case E_MIPS_MACH_OCTEON3:
return bfd_mach_mips_octeon3;
case E_MIPS_MACH_XLR:
return bfd_mach_mips_xlr;
+ case E_MIPS_MACH_IAMR2:
+ return bfd_mach_mips_interaptiv_mr2;
+
default:
switch (flags & EF_MIPS_ARCH)
{
{
asym->section = section;
/* MIPS_TEXT is a bit special, the address is not an offset
- to the base of the .text section. So substract the section
+ to the base of the .text section. So subtract the section
base address to make it an offset. */
asym->value -= section->vma;
}
{
asym->section = section;
/* MIPS_DATA is a bit special, the address is not an offset
- to the base of the .data section. So substract the section
+ to the base of the .data section. So subtract the section
base address to make it an offset. */
asym->value -= section->vma;
}
We therefore take the following approach:
- If ABFD contains a .gcc_compiled_longXX section, use it to
- determine the pointer size.
+ determine the pointer size.
- Otherwise check the type of the first relocation. Assume that
- the LP64 ABI is being used if the relocation is of type R_MIPS_64.
+ the LP64 ABI is being used if the relocation is of type R_MIPS_64.
- Otherwise punt.
did so. */
unsigned int
-_bfd_mips_elf_eh_frame_address_size (bfd *abfd, asection *sec)
+_bfd_mips_elf_eh_frame_address_size (bfd *abfd, const asection *sec)
{
if (elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS64)
return 8;
{
bfd_byte buf[4];
- BFD_ASSERT (hdr->sh_size == sizeof (Elf32_External_RegInfo));
BFD_ASSERT (hdr->contents == NULL);
+ if (hdr->sh_size != sizeof (Elf32_External_RegInfo))
+ {
+ _bfd_error_handler
+ (_("%pB: incorrect `.reginfo' section size; "
+ "expected %" PRIu64 ", got %" PRIu64),
+ abfd, (uint64_t) sizeof (Elf32_External_RegInfo),
+ (uint64_t) hdr->sh_size);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+
if (bfd_seek (abfd,
hdr->sh_offset + sizeof (Elf32_External_RegInfo) - 4,
SEEK_SET) != 0)
&intopt);
if (intopt.size < sizeof (Elf_External_Options))
{
- (*_bfd_error_handler)
- (_("%B: Warning: bad `%s' option size %u smaller than its header"),
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: warning: bad `%s' option size %u smaller than"
+ " its header"),
abfd, MIPS_ELF_OPTIONS_SECTION_NAME (abfd), intopt.size);
break;
}
break;
case SHT_MIPS_DWARF:
if (! CONST_STRNEQ (name, ".debug_")
- && ! CONST_STRNEQ (name, ".zdebug_"))
+ && ! CONST_STRNEQ (name, ".zdebug_"))
return FALSE;
break;
case SHT_MIPS_SYMBOL_LIB:
&intopt);
if (intopt.size < sizeof (Elf_External_Options))
{
- (*_bfd_error_handler)
- (_("%B: Warning: bad `%s' option size %u smaller than its header"),
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: warning: bad `%s' option size %u smaller than"
+ " its header"),
abfd, MIPS_ELF_OPTIONS_SECTION_NAME (abfd), intopt.size);
break;
}
{
hdr->sh_type = SHT_MIPS_DEBUG;
/* In a shared object on IRIX 5.3, the .mdebug section has an
- entsize of 0. FIXME: Does this matter? */
+ entsize of 0. FIXME: Does this matter? */
if (SGI_COMPAT (abfd) && (abfd->flags & DYNAMIC) != 0)
hdr->sh_entsize = 0;
else
{
hdr->sh_type = SHT_MIPS_REGINFO;
/* In a shared object on IRIX 5.3, the .reginfo section has an
- entsize of 0x18. FIXME: Does this matter? */
+ entsize of 0x18. FIXME: Does this matter? */
if (SGI_COMPAT (abfd))
{
if ((abfd->flags & DYNAMIC) != 0)
hdr->sh_entsize = sizeof (Elf_External_ABIFlags_v0);
}
else if (CONST_STRNEQ (name, ".debug_")
- || CONST_STRNEQ (name, ".zdebug_"))
+ || CONST_STRNEQ (name, ".zdebug_"))
{
hdr->sh_type = SHT_MIPS_DWARF;
{
hdr->sh_type = SHT_MIPS_SYMBOL_LIB;
/* The sh_link and sh_info fields are set in
- final_write_processing. */
+ final_write_processing. */
}
else if (CONST_STRNEQ (name, ".MIPS.events")
|| CONST_STRNEQ (name, ".MIPS.post_rel"))
elf_text_symbol->section = elf_text_section;
}
/* This code used to do *secp = bfd_und_section_ptr if
- bfd_link_pic (info). I don't know why, and that doesn't make sense,
- so I took it out. */
+ bfd_link_pic (info). I don't know why, and that doesn't make sense,
+ so I took it out. */
*secp = mips_elf_tdata (abfd)->elf_text_section;
break;
elf_data_symbol->section = elf_data_section;
}
/* This code used to do *secp = bfd_und_section_ptr if
- bfd_link_pic (info). I don't know why, and that doesn't make sense,
- so I took it out. */
+ bfd_link_pic (info). I don't know why, and that doesn't make sense,
+ so I took it out. */
*secp = mips_elf_tdata (abfd)->elf_data_section;
break;
return FALSE;
h = (struct elf_link_hash_entry *) bh;
+ h->mark = 1;
h->non_elf = 0;
h->def_regular = 1;
h->type = STT_SECTION;
if (!_bfd_elf_create_dynamic_sections (abfd, info))
return FALSE;
- /* Cache the sections created above. */
- htab->splt = bfd_get_linker_section (abfd, ".plt");
- htab->sdynbss = bfd_get_linker_section (abfd, ".dynbss");
- if (htab->is_vxworks)
- {
- htab->srelbss = bfd_get_linker_section (abfd, ".rela.bss");
- htab->srelplt = bfd_get_linker_section (abfd, ".rela.plt");
- }
- else
- htab->srelplt = bfd_get_linker_section (abfd, ".rel.plt");
- if (!htab->sdynbss
- || (htab->is_vxworks && !htab->srelbss && !bfd_link_pic (info))
- || !htab->srelplt
- || !htab->splt)
- abort ();
-
/* Do the usual VxWorks handling. */
if (htab->is_vxworks
&& !elf_vxworks_create_dynamic_sections (abfd, info, &htab->srelplt2))
return entry;
}
+/* Define the special `__gnu_absolute_zero' symbol. We only need this
+ for PIC code, as otherwise there is no load-time relocation involved
+ and local GOT entries whose value is zero at static link time will
+ retain their value at load time. */
+
+static bfd_boolean
+mips_elf_define_absolute_zero (bfd *abfd, struct bfd_link_info *info,
+ struct mips_elf_link_hash_table *htab,
+ unsigned int r_type)
+{
+ union
+ {
+ struct elf_link_hash_entry *eh;
+ struct bfd_link_hash_entry *bh;
+ }
+ hzero;
+
+ BFD_ASSERT (!htab->use_absolute_zero);
+ BFD_ASSERT (bfd_link_pic (info));
+
+ hzero.bh = NULL;
+ if (!_bfd_generic_link_add_one_symbol (info, abfd, "__gnu_absolute_zero",
+ BSF_GLOBAL, bfd_abs_section_ptr, 0,
+ NULL, FALSE, FALSE, &hzero.bh))
+ return FALSE;
+
+ BFD_ASSERT (hzero.bh != NULL);
+ hzero.eh->size = 0;
+ hzero.eh->type = STT_NOTYPE;
+ hzero.eh->other = STV_PROTECTED;
+ hzero.eh->def_regular = 1;
+ hzero.eh->non_elf = 0;
+
+ if (!mips_elf_record_global_got_symbol (hzero.eh, abfd, info, TRUE, r_type))
+ return FALSE;
+
+ htab->use_absolute_zero = TRUE;
+
+ return TRUE;
+}
+
/* Look through the relocs for a section during the first phase, and
allocate space in the global offset table and record the need for
standard MIPS and compressed procedure linkage table entries. */
extsymoff = (elf_bad_symtab (abfd)) ? 0 : symtab_hdr->sh_info;
bed = get_elf_backend_data (abfd);
- rel_end = relocs + sec->reloc_count * bed->s->int_rels_per_ext_rel;
+ rel_end = relocs + sec->reloc_count;
/* Check for the mips16 stub sections. */
unsigned long r_symndx;
/* Look at the relocation information to figure out which symbol
- this is for. */
+ this is for. */
r_symndx = mips16_stub_symndx (bed, sec, relocs, rel_end);
if (r_symndx == 0)
{
- (*_bfd_error_handler)
- (_("%B: Warning: cannot determine the target function for"
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: warning: cannot determine the target function for"
" stub section `%s'"),
abfd, name);
bfd_set_error (bfd_error_bad_value);
asection *o;
/* This stub is for a local symbol. This stub will only be
- needed if there is some relocation in this BFD, other
- than a 16 bit function call, which refers to this symbol. */
+ needed if there is some relocation in this BFD, other
+ than a 16 bit function call, which refers to this symbol. */
for (o = abfd->sections; o != NULL; o = o->next)
{
Elf_Internal_Rela *sec_relocs;
if (o == NULL)
{
/* There is no non-call reloc for this stub, so we do
- not need it. Since this function is called before
- the linker maps input sections to output sections, we
- can easily discard it by setting the SEC_EXCLUDE
- flag. */
+ not need it. Since this function is called before
+ the linker maps input sections to output sections, we
+ can easily discard it by setting the SEC_EXCLUDE
+ flag. */
sec->flags |= SEC_EXCLUDE;
return TRUE;
}
/* Record this stub in an array of local symbol stubs for
- this BFD. */
+ this BFD. */
if (mips_elf_tdata (abfd)->local_stubs == NULL)
{
unsigned long symcount;
mips_elf_tdata (abfd)->local_stubs[r_symndx] = sec;
/* We don't need to set mips16_stubs_seen in this case.
- That flag is used to see whether we need to look through
- the global symbol table for stubs. We don't need to set
- it here, because we just have a local stub. */
+ That flag is used to see whether we need to look through
+ the global symbol table for stubs. We don't need to set
+ it here, because we just have a local stub. */
}
else
{
asection **loc;
/* Look at the relocation information to figure out which symbol
- this is for. */
+ this is for. */
r_symndx = mips16_stub_symndx (bed, sec, relocs, rel_end);
if (r_symndx == 0)
{
- (*_bfd_error_handler)
- (_("%B: Warning: cannot determine the target function for"
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: warning: cannot determine the target function for"
" stub section `%s'"),
abfd, name);
bfd_set_error (bfd_error_bad_value);
asection *o;
/* This stub is for a local symbol. This stub will only be
- needed if there is some relocation (R_MIPS16_26) in this BFD
- that refers to this symbol. */
+ needed if there is some relocation (R_MIPS16_26) in this BFD
+ that refers to this symbol. */
for (o = abfd->sections; o != NULL; o = o->next)
{
Elf_Internal_Rela *sec_relocs;
if (o == NULL)
{
/* There is no non-call reloc for this stub, so we do
- not need it. Since this function is called before
- the linker maps input sections to output sections, we
- can easily discard it by setting the SEC_EXCLUDE
- flag. */
+ not need it. Since this function is called before
+ the linker maps input sections to output sections, we
+ can easily discard it by setting the SEC_EXCLUDE
+ flag. */
sec->flags |= SEC_EXCLUDE;
return TRUE;
}
/* Record this stub in an array of local symbol call_stubs for
- this BFD. */
+ this BFD. */
if (mips_elf_tdata (abfd)->local_call_stubs == NULL)
{
unsigned long symcount;
mips_elf_tdata (abfd)->local_call_stubs[r_symndx] = sec;
/* We don't need to set mips16_stubs_seen in this case.
- That flag is used to see whether we need to look through
- the global symbol table for stubs. We don't need to set
- it here, because we just have a local stub. */
+ That flag is used to see whether we need to look through
+ the global symbol table for stubs. We don't need to set
+ it here, because we just have a local stub. */
}
else
{
h = NULL;
else if (r_symndx >= extsymoff + NUM_SHDR_ENTRIES (symtab_hdr))
{
- (*_bfd_error_handler)
- (_("%B: Malformed reloc detected for section %s"),
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: malformed reloc detected for section %s"),
abfd, name);
bfd_set_error (bfd_error_bad_value);
return FALSE;
while (h->root.type == bfd_link_hash_indirect
|| h->root.type == bfd_link_hash_warning)
h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
- /* PR15323, ref flags aren't set for references in the
- same object. */
- h->root.non_ir_ref = 1;
}
}
/* Fall through. */
case R_MIPS_GOT16:
- case R_MIPS_GOT_HI16:
case R_MIPS_GOT_LO16:
case R_MIPS_GOT_PAGE:
- case R_MIPS_GOT_OFST:
case R_MIPS_GOT_DISP:
+ case R_MIPS16_GOT16:
+ case R_MICROMIPS_GOT16:
+ case R_MICROMIPS_GOT_LO16:
+ case R_MICROMIPS_GOT_PAGE:
+ case R_MICROMIPS_GOT_DISP:
+ /* If we have a symbol that will resolve to zero at static link
+ time and it is used by a GOT relocation applied to code we
+ cannot relax to an immediate zero load, then we will be using
+ the special `__gnu_absolute_zero' symbol whose value is zero
+ at dynamic load time. We ignore HI16-type GOT relocations at
+ this stage, because their handling will depend entirely on
+ the corresponding LO16-type GOT relocation. */
+ if (!call_hi16_reloc_p (r_type)
+ && h != NULL
+ && bfd_link_pic (info)
+ && !htab->use_absolute_zero
+ && UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
+ {
+ bfd_boolean rel_reloc;
+
+ if (!mips_elf_get_section_contents (abfd, sec, &contents))
+ return FALSE;
+
+ rel_reloc = mips_elf_rel_relocation_p (abfd, sec, relocs, rel);
+ howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, r_type, !rel_reloc);
+
+ if (!mips_elf_nullify_got_load (abfd, contents, rel, howto,
+ FALSE))
+ if (!mips_elf_define_absolute_zero (abfd, info, htab, r_type))
+ return FALSE;
+ }
+
+ /* Fall through. */
+ case R_MIPS_GOT_HI16:
+ case R_MIPS_GOT_OFST:
case R_MIPS_TLS_GOTTPREL:
case R_MIPS_TLS_GD:
case R_MIPS_TLS_LDM:
- case R_MIPS16_GOT16:
case R_MIPS16_TLS_GOTTPREL:
case R_MIPS16_TLS_GD:
case R_MIPS16_TLS_LDM:
- case R_MICROMIPS_GOT16:
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:
return FALSE;
if (htab->is_vxworks && !bfd_link_pic (info))
{
- (*_bfd_error_handler)
- (_("%B: GOT reloc at 0x%lx not expected in executables"),
- abfd, (unsigned long) rel->r_offset);
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: GOT reloc at %#" PRIx64 " not expected in executables"),
+ abfd, (uint64_t) rel->r_offset);
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
case R_MIPS_PC21_S2:
case R_MIPS_PC26_S2:
case R_MIPS16_26:
+ case R_MIPS16_PC16_S1:
case R_MICROMIPS_26_S1:
case R_MICROMIPS_PC7_S1:
case R_MICROMIPS_PC10_S1:
case R_MICROMIPS_CALL16:
if (h == NULL)
{
- (*_bfd_error_handler)
- (_("%B: CALL16 reloc at 0x%lx not against global symbol"),
- abfd, (unsigned long) rel->r_offset);
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: CALL16 reloc at %#" PRIx64 " not against global symbol"),
+ abfd, (uint64_t) rel->r_offset);
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
}
/* Record the need for a PLT entry. At this point we don't know
- yet if we are going to create a PLT in the first place, but
- we only record whether the relocation requires a standard MIPS
- or a compressed code entry anyway. If we don't make a PLT after
- all, then we'll just ignore these arrangements. Likewise if
- a PLT entry is not created because the symbol is satisfied
- locally. */
+ yet if we are going to create a PLT in the first place, but
+ we only record whether the relocation requires a standard MIPS
+ or a compressed code entry anyway. If we don't make a PLT after
+ all, then we'll just ignore these arrangements. Likewise if
+ a PLT entry is not created because the symbol is satisfied
+ locally. */
if (h != NULL
- && jal_reloc_p (r_type)
+ && (branch_reloc_p (r_type)
+ || mips16_branch_reloc_p (r_type)
+ || micromips_branch_reloc_p (r_type))
&& !SYMBOL_CALLS_LOCAL (info, h))
{
if (h->plt.plist == NULL)
if (h->plt.plist == NULL)
return FALSE;
- if (r_type == R_MIPS_26)
+ if (branch_reloc_p (r_type))
h->plt.plist->need_mips = TRUE;
else
h->plt.plist->need_comp = TRUE;
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"),
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: relocation %s against `%s' can not be used"
+ " when making a shared object; recompile with -fPIC"),
abfd, howto->name,
(h) ? h->root.root.string : "a local symbol");
bfd_set_error (bfd_error_bad_value);
return TRUE;
}
\f
-bfd_boolean
-_bfd_mips_relax_section (bfd *abfd, asection *sec,
- struct bfd_link_info *link_info,
- bfd_boolean *again)
-{
- Elf_Internal_Rela *internal_relocs;
- Elf_Internal_Rela *irel, *irelend;
- Elf_Internal_Shdr *symtab_hdr;
- bfd_byte *contents = NULL;
- size_t extsymoff;
- bfd_boolean changed_contents = FALSE;
- bfd_vma sec_start = sec->output_section->vma + sec->output_offset;
- Elf_Internal_Sym *isymbuf = NULL;
-
- /* We are not currently changing any sizes, so only one pass. */
- *again = FALSE;
-
- if (bfd_link_relocatable (link_info))
- return TRUE;
-
- internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL,
- link_info->keep_memory);
- if (internal_relocs == NULL)
- return TRUE;
-
- irelend = internal_relocs + sec->reloc_count
- * get_elf_backend_data (abfd)->s->int_rels_per_ext_rel;
- symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
- extsymoff = (elf_bad_symtab (abfd)) ? 0 : symtab_hdr->sh_info;
-
- for (irel = internal_relocs; irel < irelend; irel++)
- {
- bfd_vma symval;
- bfd_signed_vma sym_offset;
- unsigned int r_type;
- unsigned long r_symndx;
- asection *sym_sec;
- unsigned long instruction;
-
- /* Turn jalr into bgezal, and jr into beq, if they're marked
- with a JALR relocation, that indicate where they jump to.
- This saves some pipeline bubbles. */
- r_type = ELF_R_TYPE (abfd, irel->r_info);
- if (r_type != R_MIPS_JALR)
- continue;
-
- r_symndx = ELF_R_SYM (abfd, irel->r_info);
- /* Compute the address of the jump target. */
- if (r_symndx >= extsymoff)
- {
- struct mips_elf_link_hash_entry *h
- = ((struct mips_elf_link_hash_entry *)
- elf_sym_hashes (abfd) [r_symndx - extsymoff]);
-
- 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 a symbol is undefined, or if it may be overridden,
- skip it. */
- if (! ((h->root.root.type == bfd_link_hash_defined
- || h->root.root.type == bfd_link_hash_defweak)
- && h->root.root.u.def.section)
- || (bfd_link_pic (link_info) && ! link_info->symbolic
- && !h->root.forced_local))
- continue;
-
- sym_sec = h->root.root.u.def.section;
- if (sym_sec->output_section)
- symval = (h->root.root.u.def.value
- + sym_sec->output_section->vma
- + sym_sec->output_offset);
- else
- symval = h->root.root.u.def.value;
- }
- else
- {
- Elf_Internal_Sym *isym;
-
- /* Read this BFD's 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 relax_return;
- }
-
- isym = isymbuf + r_symndx;
- if (isym->st_shndx == SHN_UNDEF)
- continue;
- 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;
- }
-
- /* Compute branch offset, from delay slot of the jump to the
- branch target. */
- sym_offset = (symval + irel->r_addend)
- - (sec_start + irel->r_offset + 4);
-
- /* Branch offset must be properly aligned. */
- if ((sym_offset & 3) != 0)
- continue;
-
- sym_offset >>= 2;
-
- /* Check that it's in range. */
- if (sym_offset < -0x8000 || sym_offset >= 0x8000)
- continue;
-
- /* Get the section contents if we haven't done so already. */
- if (!mips_elf_get_section_contents (abfd, sec, &contents))
- goto relax_return;
-
- instruction = bfd_get_32 (abfd, contents + irel->r_offset);
-
- /* If it was jalr <reg>, turn it into bgezal $zero, <target>. */
- if ((instruction & 0xfc1fffff) == 0x0000f809)
- instruction = 0x04110000;
- /* If it was jr <reg>, turn it into b <target>. */
- else if ((instruction & 0xfc1fffff) == 0x00000008)
- instruction = 0x10000000;
- else
- continue;
-
- instruction |= (sym_offset & 0xffff);
- bfd_put_32 (abfd, instruction, contents + irel->r_offset);
- changed_contents = TRUE;
- }
-
- if (contents != NULL
- && elf_section_data (sec)->this_hdr.contents != contents)
- {
- if (!changed_contents && !link_info->keep_memory)
- free (contents);
- else
- {
- /* Cache the section contents for elf_link_input_bfd. */
- elf_section_data (sec)->this_hdr.contents = contents;
- }
- }
- return TRUE;
-
- relax_return:
- if (contents != NULL
- && elf_section_data (sec)->this_hdr.contents != contents)
- free (contents);
- return FALSE;
-}
-\f
/* Allocate space for global sym dynamic relocs. */
static bfd_boolean
if (h->root.type == bfd_link_hash_undefweak)
{
- /* Do not copy relocations for undefined weak symbols with
- non-default visibility. */
- if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
+ /* Do not copy relocations for undefined weak symbols that
+ we are not going to export. */
+ if (UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
do_copy = FALSE;
/* Make sure undefined weak symbols are output as a dynamic
bfd *dynobj;
struct mips_elf_link_hash_entry *hmips;
struct mips_elf_link_hash_table *htab;
+ asection *s, *srel;
htab = mips_elf_hash_table (info);
BFD_ASSERT (htab != NULL);
/* Make sure we know what is going on here. */
BFD_ASSERT (dynobj != NULL
&& (h->needs_plt
- || h->u.weakdef != NULL
+ || h->is_weakalias
|| (h->def_dynamic
&& h->ref_regular
&& !h->def_regular)));
the symbol to the stub location. This is required to make
function pointers compare as equal between the normal
executable and the shared library. */
- if (!h->def_regular)
+ if (!h->def_regular
+ && !bfd_is_abs_section (htab->sstubs->output_section))
{
hmips->needs_lazy_stub = TRUE;
htab->lazy_stub_count++;
bfd_boolean newabi_p = NEWABI_P (info->output_bfd);
/* If this is the first symbol to need a PLT entry, then make some
- basic setup. Also work out PLT entry sizes. We'll need them
- for PLT offset calculations. */
+ basic setup. Also work out PLT entry sizes. We'll need them
+ for PLT offset calculations. */
if (htab->plt_mips_offset + htab->plt_comp_offset == 0)
{
- BFD_ASSERT (htab->sgotplt->size == 0);
+ BFD_ASSERT (htab->root.sgotplt->size == 0);
BFD_ASSERT (htab->plt_got_index == 0);
/* If we're using the PLT additions to the psABI, each PLT
Encourage better cache usage by aligning. We do this
lazily to avoid pessimizing traditional objects. */
if (!htab->is_vxworks
- && !bfd_set_section_alignment (dynobj, htab->splt, 5))
+ && !bfd_set_section_alignment (dynobj, htab->root.splt, 5))
return FALSE;
/* Make sure that .got.plt is word-aligned. We do this lazily
for the same reason as above. */
- if (!bfd_set_section_alignment (dynobj, htab->sgotplt,
+ if (!bfd_set_section_alignment (dynobj, htab->root.sgotplt,
MIPS_ELF_LOG_FILE_ALIGN (dynobj)))
return FALSE;
return FALSE;
/* There are no defined MIPS16 or microMIPS PLT entries for VxWorks,
- n32 or n64, so always use a standard entry there.
+ n32 or n64, so always use a standard entry there.
- If the symbol has a MIPS16 call stub and gets a PLT entry, then
- all MIPS16 calls will go via that stub, and there is no benefit
- to having a MIPS16 entry. And in the case of call_stub a
- standard entry actually has to be used as the stub ends with a J
- instruction. */
+ If the symbol has a MIPS16 call stub and gets a PLT entry, then
+ all MIPS16 calls will go via that stub, and there is no benefit
+ to having a MIPS16 entry. And in the case of call_stub a
+ standard entry actually has to be used as the stub ends with a J
+ instruction. */
if (newabi_p
|| htab->is_vxworks
|| hmips->call_stub
}
/* Otherwise, if there are no direct calls to the function, we
- have a free choice of whether to use standard or compressed
- entries. Prefer microMIPS entries if the object is known to
- contain microMIPS code, so that it becomes possible to create
- pure microMIPS binaries. Prefer standard entries otherwise,
- because MIPS16 ones are no smaller and are usually slower. */
+ have a free choice of whether to use standard or compressed
+ entries. Prefer microMIPS entries if the object is known to
+ contain microMIPS code, so that it becomes possible to create
+ pure microMIPS binaries. Prefer standard entries otherwise,
+ because MIPS16 ones are no smaller and are usually slower. */
if (!h->plt.plist->need_mips && !h->plt.plist->need_comp)
{
if (micromips_p)
hmips->use_plt_entry = TRUE;
/* Make room for the R_MIPS_JUMP_SLOT relocation. */
- htab->srelplt->size += (htab->is_vxworks
- ? MIPS_ELF_RELA_SIZE (dynobj)
- : MIPS_ELF_REL_SIZE (dynobj));
+ htab->root.srelplt->size += (htab->is_vxworks
+ ? MIPS_ELF_RELA_SIZE (dynobj)
+ : MIPS_ELF_REL_SIZE (dynobj));
/* Make room for the .rela.plt.unloaded relocations. */
if (htab->is_vxworks && !bfd_link_pic (info))
/* If this is a weak symbol, and there is a real definition, the
processor independent code will have arranged for us to see the
real definition first, and we can just use the same value. */
- if (h->u.weakdef != NULL)
+ if (h->is_weakalias)
{
- BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined
- || h->u.weakdef->root.type == bfd_link_hash_defweak);
- h->root.u.def.section = h->u.weakdef->root.u.def.section;
- h->root.u.def.value = h->u.weakdef->root.u.def.value;
+ struct elf_link_hash_entry *def = weakdef (h);
+ BFD_ASSERT (def->root.type == bfd_link_hash_defined);
+ h->root.u.def.section = def->root.u.def.section;
+ h->root.u.def.value = def->root.u.def.value;
return TRUE;
}
some that we can't convert. */
if (!htab->use_plts_and_copy_relocs || bfd_link_pic (info))
{
- (*_bfd_error_handler) (_("non-dynamic relocations refer to "
- "dynamic symbol %s"),
- h->root.root.string);
+ _bfd_error_handler (_("non-dynamic relocations refer to "
+ "dynamic symbol %s"),
+ h->root.root.string);
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
both the dynamic object and the regular object will refer to the
same memory location for the variable. */
+ if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
+ {
+ s = htab->root.sdynrelro;
+ srel = htab->root.sreldynrelro;
+ }
+ else
+ {
+ s = htab->root.sdynbss;
+ srel = htab->root.srelbss;
+ }
if ((h->root.u.def.section->flags & SEC_ALLOC) != 0)
{
if (htab->is_vxworks)
- htab->srelbss->size += sizeof (Elf32_External_Rela);
+ srel->size += sizeof (Elf32_External_Rela);
else
mips_elf_allocate_dynamic_relocations (dynobj, info, 1);
h->needs_copy = 1;
dynamic will now refer to the local copy instead. */
hmips->possibly_dynamic_relocs = 0;
- return _bfd_elf_adjust_dynamic_copy (info, h, htab->sdynbss);
+ return _bfd_elf_adjust_dynamic_copy (info, h, s);
}
\f
/* This function is called after all the input files have been read,
/* The .reginfo section has a fixed size. */
sect = bfd_get_section_by_name (output_bfd, ".reginfo");
if (sect != NULL)
- bfd_set_section_size (output_bfd, sect, sizeof (Elf32_External_RegInfo));
+ {
+ bfd_set_section_size (output_bfd, sect, sizeof (Elf32_External_RegInfo));
+ sect->flags |= SEC_FIXED_SIZE | SEC_HAS_CONTENTS;
+ }
/* The .MIPS.abiflags section has a fixed size. */
sect = bfd_get_section_by_name (output_bfd, ".MIPS.abiflags");
if (sect != NULL)
- bfd_set_section_size (output_bfd, sect, sizeof (Elf_External_ABIFlags_v0));
+ {
+ bfd_set_section_size (output_bfd, sect,
+ sizeof (Elf_External_ABIFlags_v0));
+ sect->flags |= SEC_FIXED_SIZE | SEC_HAS_CONTENTS;
+ }
hti.info = info;
hti.output_bfd = output_bfd;
htab = mips_elf_hash_table (info);
BFD_ASSERT (htab != NULL);
- s = htab->sgot;
+ s = htab->root.sgot;
if (s == NULL)
return TRUE;
}
val += isa_bit;
/* For VxWorks, point at the PLT load stub rather than the lazy
- resolution stub; this stub will become the canonical function
- address. */
+ resolution stub; this stub will become the canonical function
+ address. */
if (htab->is_vxworks)
val += 8;
- h->root.root.u.def.section = htab->splt;
+ h->root.root.u.def.section = htab->root.splt;
h->root.root.u.def.value = val;
h->root.other = other;
}
}
/* Figure out the size of the PLT header if we know that we
- are using it. For the sake of cache alignment always use
- a standard header whenever any standard entries are present
- even if microMIPS entries are present as well. This also
- lets the microMIPS header rely on the value of $v0 only set
- by microMIPS entries, for a small size reduction.
-
- Set symbol table entry values for symbols that use the
- address of their PLT entry now that we can calculate it.
-
- Also create the _PROCEDURE_LINKAGE_TABLE_ symbol if we
- haven't already in _bfd_elf_create_dynamic_sections. */
- if (htab->splt && htab->plt_mips_offset + htab->plt_comp_offset != 0)
+ are using it. For the sake of cache alignment always use
+ a standard header whenever any standard entries are present
+ even if microMIPS entries are present as well. This also
+ lets the microMIPS header rely on the value of $v0 only set
+ by microMIPS entries, for a small size reduction.
+
+ Set symbol table entry values for symbols that use the
+ address of their PLT entry now that we can calculate it.
+
+ Also create the _PROCEDURE_LINKAGE_TABLE_ symbol if we
+ haven't already in _bfd_elf_create_dynamic_sections. */
+ if (htab->root.splt && htab->plt_mips_offset + htab->plt_comp_offset != 0)
{
bfd_boolean micromips_p = (MICROMIPS_P (output_bfd)
&& !htab->plt_mips_offset);
bfd_vma size;
BFD_ASSERT (htab->use_plts_and_copy_relocs);
- BFD_ASSERT (htab->sgotplt->size == 0);
- BFD_ASSERT (htab->splt->size == 0);
+ BFD_ASSERT (htab->root.sgotplt->size == 0);
+ BFD_ASSERT (htab->root.splt->size == 0);
if (htab->is_vxworks && bfd_link_pic (info))
size = 4 * ARRAY_SIZE (mips_vxworks_shared_plt0_entry);
htab->plt_header_is_comp = micromips_p;
htab->plt_header_size = size;
- htab->splt->size = (size
- + htab->plt_mips_offset
- + htab->plt_comp_offset);
- htab->sgotplt->size = (htab->plt_got_index
- * MIPS_ELF_GOT_SIZE (dynobj));
+ htab->root.splt->size = (size
+ + htab->plt_mips_offset
+ + htab->plt_comp_offset);
+ htab->root.sgotplt->size = (htab->plt_got_index
+ * MIPS_ELF_GOT_SIZE (dynobj));
mips_elf_link_hash_traverse (htab, mips_elf_set_plt_sym_value, info);
if (htab->root.hplt == NULL)
{
- h = _bfd_elf_define_linkage_sym (dynobj, info, htab->splt,
+ h = _bfd_elf_define_linkage_sym (dynobj, info, htab->root.splt,
"_PROCEDURE_LINKAGE_TABLE_");
htab->root.hplt = h;
if (h == NULL)
asection *target;
/* If this relocation section applies to a read only
- section, then we probably need a DT_TEXTREL entry.
- If the relocation section is .rel(a).dyn, we always
- assert a DT_TEXTREL entry rather than testing whether
- there exists a relocation to a read only section or
- not. */
+ section, then we probably need a DT_TEXTREL entry.
+ If the relocation section is .rel(a).dyn, we always
+ assert a DT_TEXTREL entry rather than testing whether
+ there exists a relocation to a read only section or
+ not. */
outname = bfd_get_section_name (output_bfd,
s->output_section);
target = bfd_get_section_by_name (output_bfd, outname + 4);
else if (SGI_COMPAT (output_bfd)
&& CONST_STRNEQ (name, ".compact_rel"))
s->size += mips_elf_hash_table (info)->compact_rel_size;
- else if (s == htab->splt)
+ else if (s == htab->root.splt)
{
/* If the last PLT entry has a branch delay slot, allocate
room for an extra nop to fill the delay slot. This is
s->size += 4;
}
else if (! CONST_STRNEQ (name, ".init")
- && s != htab->sgot
- && s != htab->sgotplt
+ && s != htab->root.sgot
+ && s != htab->root.sgotplt
&& s != htab->sstubs
- && s != htab->sdynbss)
+ && s != htab->root.sdynbss
+ && s != htab->root.sdynrelro)
{
/* It's not one of our sections, so don't allocate space. */
continue;
}
else
{
- if (sreldyn && sreldyn->size > 0)
+ if (sreldyn && sreldyn->size > 0
+ && !bfd_is_abs_section (sreldyn->output_section))
{
if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_REL, 0))
return FALSE;
&& !MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_OPTIONS, 0))
return FALSE;
}
- if (htab->splt->size > 0)
+ if (htab->root.splt->size > 0)
{
if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_PLTREL, 0))
return FALSE;
const Elf_Internal_Rela *relend;
bfd_vma addend = 0;
bfd_boolean use_saved_addend_p = FALSE;
- const struct elf_backend_data *bed;
- bed = get_elf_backend_data (output_bfd);
- relend = relocs + input_section->reloc_count * bed->s->int_rels_per_ext_rel;
+ relend = relocs + input_section->reloc_count;
for (rel = relocs; rel < relend; ++rel)
{
const char *name;
reloc_howto_type *howto;
bfd_boolean cross_mode_jump_p = FALSE;
/* TRUE if the relocation is a RELA relocation, rather than a
- REL relocation. */
+ REL relocation. */
bfd_boolean rela_relocation_p = TRUE;
unsigned int r_type = ELF_R_TYPE (output_bfd, rel->r_info);
const char *msg;
name = bfd_elf_sym_name (input_bfd, symtab_hdr,
local_syms + r_symndx,
sec);
- (*_bfd_error_handler)
- (_("%B: Can't find matching LO16 reloc against `%s' for %s at 0x%lx in section `%A'"),
- input_bfd, input_section, name, howto->name,
- rel->r_offset);
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: can't find matching LO16 reloc against `%s'"
+ " for %s at %#" PRIx64 " in section `%pA'"),
+ input_bfd, name,
+ howto->name, (uint64_t) rel->r_offset, input_section);
}
}
else
/* Figure out what value we are supposed to relocate. */
switch (mips_elf_calculate_relocation (output_bfd, input_bfd,
- input_section, info, rel,
- addend, howto, local_syms,
- local_sections, &value,
- &name, &cross_mode_jump_p,
+ input_section, contents,
+ info, rel, addend, howto,
+ local_syms, local_sections,
+ &value, &name, &cross_mode_jump_p,
use_saved_addend_p))
{
case bfd_reloc_continue:
htab->small_data_overflow_reported = TRUE;
(*info->callbacks->einfo) ("%P: %s\n", msg);
}
- if (! ((*info->callbacks->reloc_overflow)
- (info, NULL, name, howto->name, (bfd_vma) 0,
- input_bfd, input_section, rel->r_offset)))
- return FALSE;
+ (*info->callbacks->reloc_overflow)
+ (info, NULL, name, howto->name, (bfd_vma) 0,
+ input_bfd, input_section, rel->r_offset);
}
break;
case bfd_reloc_outofrange:
msg = NULL;
if (jal_reloc_p (howto->type))
- msg = _("JALX to a non-word-aligned address");
+ msg = (cross_mode_jump_p
+ ? _("cannot convert a jump to JALX "
+ "for a non-word-aligned address")
+ : (howto->type == R_MIPS16_26
+ ? _("jump to a non-word-aligned address")
+ : _("jump to a non-instruction-aligned address")));
+ else if (b_reloc_p (howto->type))
+ msg = (cross_mode_jump_p
+ ? _("cannot convert a branch to JALX "
+ "for a non-word-aligned address")
+ : _("branch to a non-instruction-aligned address"));
else if (aligned_pcrel_reloc_p (howto->type))
msg = _("PC-relative load from unaligned address");
if (msg)
BFD_ASSERT (htab->use_plts_and_copy_relocs);
BFD_ASSERT (h->dynindx != -1);
- BFD_ASSERT (htab->splt != NULL);
+ BFD_ASSERT (htab->root.splt != NULL);
BFD_ASSERT (got_index != MINUS_ONE);
BFD_ASSERT (!h->def_regular);
/* Calculate the address of the PLT header. */
isa_bit = htab->plt_header_is_comp;
- header_address = (htab->splt->output_section->vma
- + htab->splt->output_offset + isa_bit);
+ header_address = (htab->root.splt->output_section->vma
+ + htab->root.splt->output_offset + isa_bit);
/* Calculate the address of the .got.plt entry. */
- got_address = (htab->sgotplt->output_section->vma
- + htab->sgotplt->output_offset
+ got_address = (htab->root.sgotplt->output_section->vma
+ + htab->root.sgotplt->output_offset
+ got_index * MIPS_ELF_GOT_SIZE (dynobj));
got_address_high = ((got_address + 0x8000) >> 16) & 0xffff;
got_address_low = got_address & 0xffff;
+ /* The PLT sequence is not safe for N64 if .got.plt entry's address
+ cannot be loaded in two instructions. */
+ if (ABI_64_P (output_bfd)
+ && ((got_address + 0x80008000) & ~(bfd_vma) 0xffffffff) != 0)
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: `%pA' entry VMA of %#" PRIx64 " outside the 32-bit range "
+ "supported; consider using `-Ttext-segment=...'"),
+ output_bfd,
+ htab->root.sgotplt->output_section,
+ (int64_t) got_address);
+ bfd_set_error (bfd_error_no_error);
+ return FALSE;
+ }
+
/* Initially point the .got.plt entry at the PLT header. */
- loc = (htab->sgotplt->contents + got_index * MIPS_ELF_GOT_SIZE (dynobj));
+ loc = (htab->root.sgotplt->contents
+ + got_index * MIPS_ELF_GOT_SIZE (dynobj));
if (ABI_64_P (output_bfd))
bfd_put_64 (output_bfd, header_address, loc);
else
bfd_put_32 (output_bfd, header_address, loc);
/* Now handle the PLT itself. First the standard entry (the order
- does not matter, we just have to pick one). */
+ does not matter, we just have to pick one). */
if (h->plt.plist->mips_offset != MINUS_ONE)
{
const bfd_vma *plt_entry;
plt_offset = htab->plt_header_size + h->plt.plist->mips_offset;
- BFD_ASSERT (plt_offset <= htab->splt->size);
+ BFD_ASSERT (plt_offset <= htab->root.splt->size);
/* Find out where the .plt entry should go. */
- loc = htab->splt->contents + plt_offset;
+ loc = htab->root.splt->contents + plt_offset;
/* Pick the load opcode. */
load = MIPS_ELF_LOAD_WORD (output_bfd);
plt_offset = (htab->plt_header_size + htab->plt_mips_offset
+ h->plt.plist->comp_offset);
- BFD_ASSERT (plt_offset <= htab->splt->size);
+ BFD_ASSERT (plt_offset <= htab->root.splt->size);
/* Find out where the .plt entry should go. */
- loc = htab->splt->contents + plt_offset;
+ loc = htab->root.splt->contents + plt_offset;
/* Fill in the PLT entry itself. */
if (!MICROMIPS_P (output_bfd))
BFD_ASSERT (got_address % 4 == 0);
- loc_address = (htab->splt->output_section->vma
- + htab->splt->output_offset + plt_offset);
+ loc_address = (htab->root.splt->output_section->vma
+ + htab->root.splt->output_offset + plt_offset);
gotpc_offset = got_address - ((loc_address | 3) ^ 3);
/* ADDIUPC has a span of +/-16MB, check we're in range. */
if (gotpc_offset + 0x1000000 >= 0x2000000)
{
- (*_bfd_error_handler)
- (_("%B: `%A' offset of %ld from `%A' "
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: `%pA' offset of %" PRId64 " from `%pA' "
"beyond the range of ADDIUPC"),
output_bfd,
- htab->sgotplt->output_section,
- htab->splt->output_section,
- (long) gotpc_offset);
+ htab->root.sgotplt->output_section,
+ (int64_t) gotpc_offset,
+ htab->root.splt->output_section);
bfd_set_error (bfd_error_no_error);
return FALSE;
}
}
/* Emit an R_MIPS_JUMP_SLOT relocation against the .got.plt entry. */
- mips_elf_output_dynamic_relocation (output_bfd, htab->srelplt,
+ mips_elf_output_dynamic_relocation (output_bfd, htab->root.srelplt,
got_index - 2, h->dynindx,
R_MIPS_JUMP_SLOT, got_address);
BFD_ASSERT (h->dynindx != -1
|| h->forced_local);
- sgot = htab->sgot;
+ sgot = htab->root.sgot;
g = htab->got_info;
BFD_ASSERT (g != NULL);
&e)))
{
offset = p->gotidx;
- BFD_ASSERT (offset > 0 && offset < htab->sgot->size);
+ BFD_ASSERT (offset > 0 && offset < htab->root.sgot->size);
if (bfd_link_pic (info)
|| (elf_hash_table (info)->dynamic_sections_created
&& p->d.h != NULL
sym->st_info = ELF_ST_INFO (STB_GLOBAL, STT_SECTION);
sym->st_value = 1;
}
- else if (strcmp (name, "_gp_disp") == 0 && ! NEWABI_P (output_bfd))
- {
- sym->st_shndx = SHN_ABS;
- sym->st_info = ELF_ST_INFO (STB_GLOBAL, STT_SECTION);
- sym->st_value = elf_gp (output_bfd);
- }
else if (SGI_COMPAT (output_bfd))
{
if (strcmp (name, mips_elf_dynsym_rtproc_names[0]) == 0
gotplt_index = h->plt.plist->gotplt_index;
BFD_ASSERT (h->dynindx != -1);
- BFD_ASSERT (htab->splt != NULL);
+ BFD_ASSERT (htab->root.splt != NULL);
BFD_ASSERT (gotplt_index != MINUS_ONE);
- BFD_ASSERT (plt_offset <= htab->splt->size);
+ BFD_ASSERT (plt_offset <= htab->root.splt->size);
/* Calculate the address of the .plt entry. */
- plt_address = (htab->splt->output_section->vma
- + htab->splt->output_offset
+ plt_address = (htab->root.splt->output_section->vma
+ + htab->root.splt->output_offset
+ plt_offset);
/* Calculate the address of the .got.plt entry. */
- got_address = (htab->sgotplt->output_section->vma
- + htab->sgotplt->output_offset
+ got_address = (htab->root.sgotplt->output_section->vma
+ + htab->root.sgotplt->output_offset
+ gotplt_index * MIPS_ELF_GOT_SIZE (output_bfd));
/* Calculate the offset of the .got.plt entry from
/* Fill in the initial value of the .got.plt entry. */
bfd_put_32 (output_bfd, plt_address,
- (htab->sgotplt->contents
+ (htab->root.sgotplt->contents
+ gotplt_index * MIPS_ELF_GOT_SIZE (output_bfd)));
/* Find out where the .plt entry should go. */
- loc = htab->splt->contents + plt_offset;
+ loc = htab->root.splt->contents + plt_offset;
if (bfd_link_pic (info))
{
}
/* Emit an R_MIPS_JUMP_SLOT relocation against the .got.plt entry. */
- loc = (htab->srelplt->contents
+ loc = (htab->root.srelplt->contents
+ gotplt_index * sizeof (Elf32_External_Rela));
rel.r_offset = got_address;
rel.r_info = ELF32_R_INFO (h->dynindx, R_MIPS_JUMP_SLOT);
BFD_ASSERT (h->dynindx != -1 || h->forced_local);
- sgot = htab->sgot;
+ sgot = htab->root.sgot;
g = htab->got_info;
BFD_ASSERT (g != NULL);
if (h->needs_copy)
{
Elf_Internal_Rela rel;
+ asection *srel;
+ bfd_byte *loc;
BFD_ASSERT (h->dynindx != -1);
+ h->root.u.def.value);
rel.r_info = ELF32_R_INFO (h->dynindx, R_MIPS_COPY);
rel.r_addend = 0;
- bfd_elf32_swap_reloca_out (output_bfd, &rel,
- htab->srelbss->contents
- + (htab->srelbss->reloc_count
- * sizeof (Elf32_External_Rela)));
- ++htab->srelbss->reloc_count;
+ if (h->root.u.def.section == htab->root.sdynrelro)
+ srel = htab->root.sreldynrelro;
+ else
+ srel = htab->root.srelbss;
+ loc = srel->contents + srel->reloc_count * sizeof (Elf32_External_Rela);
+ bfd_elf32_swap_reloca_out (output_bfd, &rel, loc);
+ ++srel->reloc_count;
}
/* If this is a mips16/microMIPS symbol, force the value to be even. */
plt_entry = micromips_o32_exec_plt0_entry;
/* Calculate the value of .got.plt. */
- gotplt_value = (htab->sgotplt->output_section->vma
- + htab->sgotplt->output_offset);
+ gotplt_value = (htab->root.sgotplt->output_section->vma
+ + htab->root.sgotplt->output_offset);
gotplt_value_high = ((gotplt_value + 0x8000) >> 16) & 0xffff;
gotplt_value_low = gotplt_value & 0xffff;
/* The PLT sequence is not safe for N64 if .got.plt's address can
not be loaded in two instructions. */
- BFD_ASSERT ((gotplt_value & ~(bfd_vma) 0x7fffffff) == 0
- || ~(gotplt_value | 0x7fffffff) == 0);
+ if (ABI_64_P (output_bfd)
+ && ((gotplt_value + 0x80008000) & ~(bfd_vma) 0xffffffff) != 0)
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: `%pA' start VMA of %#" PRIx64 " outside the 32-bit range "
+ "supported; consider using `-Ttext-segment=...'"),
+ output_bfd,
+ htab->root.sgotplt->output_section,
+ (int64_t) gotplt_value);
+ bfd_set_error (bfd_error_no_error);
+ return FALSE;
+ }
/* Install the PLT header. */
- loc = htab->splt->contents;
+ loc = htab->root.splt->contents;
if (plt_entry == micromips_o32_exec_plt0_entry)
{
bfd_vma gotpc_offset;
BFD_ASSERT (gotplt_value % 4 == 0);
- loc_address = (htab->splt->output_section->vma
- + htab->splt->output_offset);
+ loc_address = (htab->root.splt->output_section->vma
+ + htab->root.splt->output_offset);
gotpc_offset = gotplt_value - ((loc_address | 3) ^ 3);
/* ADDIUPC has a span of +/-16MB, check we're in range. */
if (gotpc_offset + 0x1000000 >= 0x2000000)
{
- (*_bfd_error_handler)
- (_("%B: `%A' offset of %ld from `%A' beyond the range of ADDIUPC"),
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: `%pA' offset of %" PRId64 " from `%pA' "
+ "beyond the range of ADDIUPC"),
output_bfd,
- htab->sgotplt->output_section,
- htab->splt->output_section,
- (long) gotpc_offset);
+ htab->root.sgotplt->output_section,
+ (int64_t) gotpc_offset,
+ htab->root.splt->output_section);
bfd_set_error (bfd_error_no_error);
return FALSE;
}
got_value_low = got_value & 0xffff;
/* Calculate the address of the PLT header. */
- plt_address = htab->splt->output_section->vma + htab->splt->output_offset;
+ plt_address = (htab->root.splt->output_section->vma
+ + htab->root.splt->output_offset);
/* Install the PLT header. */
- loc = htab->splt->contents;
+ loc = htab->root.splt->contents;
bfd_put_32 (output_bfd, plt_entry[0] | got_value_high, loc);
bfd_put_32 (output_bfd, plt_entry[1] | got_value_low, loc + 4);
bfd_put_32 (output_bfd, plt_entry[2], loc + 8);
/* We just need to copy the entry byte-by-byte. */
for (i = 0; i < ARRAY_SIZE (mips_vxworks_shared_plt0_entry); i++)
bfd_put_32 (output_bfd, mips_vxworks_shared_plt0_entry[i],
- htab->splt->contents + i * 4);
+ htab->root.splt->contents + i * 4);
}
/* Finish up the dynamic sections. */
sdyn = bfd_get_linker_section (dynobj, ".dynamic");
- sgot = htab->sgot;
+ sgot = htab->root.sgot;
gg = htab->got_info;
if (elf_hash_table (info)->dynamic_sections_created)
break;
case DT_PLTGOT:
- s = htab->sgot;
+ s = htab->root.sgot;
dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
break;
case DT_MIPS_PLTGOT:
- s = htab->sgotplt;
+ s = htab->root.sgotplt;
dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
break;
}
/* In case if we don't have global got symbols we default
to setting DT_MIPS_GOTSYM to the same value as
- DT_MIPS_SYMTABNO, so we just fall through. */
+ DT_MIPS_SYMTABNO. */
+ /* Fall through. */
case DT_MIPS_SYMTABNO:
name = ".dynsym";
dyn.d_un.d_ptr = s->vma;
break;
- case DT_RELASZ:
- BFD_ASSERT (htab->is_vxworks);
- /* The count does not include the JUMP_SLOT relocations. */
- if (htab->srelplt)
- dyn.d_un.d_val -= htab->srelplt->size;
- break;
-
case DT_PLTREL:
BFD_ASSERT (htab->use_plts_and_copy_relocs);
if (htab->is_vxworks)
case DT_PLTRELSZ:
BFD_ASSERT (htab->use_plts_and_copy_relocs);
- dyn.d_un.d_val = htab->srelplt->size;
+ dyn.d_un.d_val = htab->root.srelplt->size;
break;
case DT_JMPREL:
BFD_ASSERT (htab->use_plts_and_copy_relocs);
- dyn.d_un.d_ptr = (htab->srelplt->output_section->vma
- + htab->srelplt->output_offset);
+ dyn.d_un.d_ptr = (htab->root.srelplt->output_section->vma
+ + htab->root.srelplt->output_offset);
break;
case DT_TEXTREL:
: sizeof (Elf32_External_Rel)));
/* Adjust the section size too. Tools like the prelinker
can reasonably expect the values to the same. */
+ BFD_ASSERT (!bfd_is_abs_section (s->output_section));
elf_section_data (s->output_section)->this_hdr.sh_size
= dyn.d_un.d_val;
break;
}
}
- if (htab->splt && htab->splt->size > 0)
+ if (htab->root.splt && htab->root.splt->size > 0)
{
if (htab->is_vxworks)
{
val = E_MIPS_ARCH_2;
break;
+ case bfd_mach_mips4010:
+ val = E_MIPS_ARCH_2 | E_MIPS_MACH_4010;
+ break;
+
case bfd_mach_mips4000:
case bfd_mach_mips4300:
case bfd_mach_mips4400:
val = E_MIPS_ARCH_3;
break;
- case bfd_mach_mips4010:
- val = E_MIPS_ARCH_3 | E_MIPS_MACH_4010;
- break;
-
case bfd_mach_mips4100:
val = E_MIPS_ARCH_3 | E_MIPS_MACH_4100;
break;
val = E_MIPS_ARCH_64 | E_MIPS_MACH_SB1;
break;
- case bfd_mach_mips_loongson_3a:
- val = E_MIPS_ARCH_64R2 | E_MIPS_MACH_LS3A;
+ case bfd_mach_mips_gs464:
+ val = E_MIPS_ARCH_64R2 | E_MIPS_MACH_GS464;
+ break;
+
+ case bfd_mach_mips_gs464e:
+ val = E_MIPS_ARCH_64R2 | E_MIPS_MACH_GS464E;
+ break;
+
+ case bfd_mach_mips_gs264e:
+ val = E_MIPS_ARCH_64R2 | E_MIPS_MACH_GS264E;
break;
case bfd_mach_mips_octeon:
val = E_MIPS_ARCH_32R2;
break;
+ case bfd_mach_mips_interaptiv_mr2:
+ val = E_MIPS_ARCH_32R2 | E_MIPS_MACH_IAMR2;
+ break;
+
case bfd_mach_mipsisa64r2:
case bfd_mach_mipsisa64r3:
case bfd_mach_mipsisa64r5:
return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
}
-/* Update the got entry reference counts for the section being removed. */
-
-bfd_boolean
-_bfd_mips_elf_gc_sweep_hook (bfd *abfd ATTRIBUTE_UNUSED,
- struct bfd_link_info *info ATTRIBUTE_UNUSED,
- asection *sec ATTRIBUTE_UNUSED,
- const Elf_Internal_Rela *relocs ATTRIBUTE_UNUSED)
-{
-#if 0
- Elf_Internal_Shdr *symtab_hdr;
- struct elf_link_hash_entry **sym_hashes;
- bfd_signed_vma *local_got_refcounts;
- const Elf_Internal_Rela *rel, *relend;
- unsigned long r_symndx;
- struct elf_link_hash_entry *h;
-
- if (bfd_link_relocatable (info))
- return TRUE;
-
- symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
- sym_hashes = elf_sym_hashes (abfd);
- local_got_refcounts = elf_local_got_refcounts (abfd);
-
- relend = relocs + sec->reloc_count;
- for (rel = relocs; rel < relend; rel++)
- switch (ELF_R_TYPE (abfd, rel->r_info))
- {
- case R_MIPS16_GOT16:
- case R_MIPS16_CALL16:
- case R_MIPS_GOT16:
- case R_MIPS_CALL16:
- case R_MIPS_CALL_HI16:
- case R_MIPS_CALL_LO16:
- case R_MIPS_GOT_HI16:
- case R_MIPS_GOT_LO16:
- 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. */
- break;
-
- default:
- break;
- }
-#endif
-
- return TRUE;
-}
-
/* Prevent .MIPS.abiflags from being discarded with --gc-sections. */
bfd_boolean
if (indmips->has_nonpic_branches)
dirmips->has_nonpic_branches = TRUE;
}
+
+/* Take care of the special `__gnu_absolute_zero' symbol and ignore attempts
+ to hide it. It has to remain global (it will also be protected) so as to
+ be assigned a global GOT entry, which will then remain unchanged at load
+ time. */
+
+void
+_bfd_mips_elf_hide_symbol (struct bfd_link_info *info,
+ struct elf_link_hash_entry *entry,
+ bfd_boolean force_local)
+{
+ struct mips_elf_link_hash_table *htab;
+
+ htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+ if (htab->use_absolute_zero
+ && strcmp (entry->root.root.string, "__gnu_absolute_zero") == 0)
+ return;
+
+ _bfd_elf_link_hash_hide_symbol (info, entry, force_local);
+}
\f
#define PDR_SIZE 32
bfd_boolean
_bfd_mips_elf_write_section (bfd *output_bfd,
struct bfd_link_info *link_info ATTRIBUTE_UNUSED,
- asection *sec, bfd_byte *contents)
+ asection *sec, bfd_byte *contents)
{
bfd_byte *to, *from, *end;
int i;
line_ptr, discriminator_ptr,
dwarf_debug_sections,
ABI_64_P (abfd) ? 8 : 0,
- &elf_tdata (abfd)->dwarf2_find_line_info))
- return TRUE;
+ &elf_tdata (abfd)->dwarf2_find_line_info)
+ || _bfd_dwarf1_find_nearest_line (abfd, symbols, section, offset,
+ filename_ptr, functionname_ptr,
+ line_ptr))
+ {
+ /* PR 22789: If the function name or filename was not found through
+ the debug information, then try an ordinary lookup instead. */
+ if ((functionname_ptr != NULL && *functionname_ptr == NULL)
+ || (filename_ptr != NULL && *filename_ptr == NULL))
+ {
+ /* Do not override already discovered names. */
+ if (functionname_ptr != NULL && *functionname_ptr != NULL)
+ functionname_ptr = NULL;
- if (_bfd_dwarf1_find_nearest_line (abfd, symbols, section, offset,
- filename_ptr, functionname_ptr,
- line_ptr))
- return TRUE;
+ if (filename_ptr != NULL && *filename_ptr != NULL)
+ filename_ptr = NULL;
+
+ _bfd_elf_find_function (abfd, symbols, section, offset,
+ filename_ptr, functionname_ptr);
+ }
+
+ return TRUE;
+ }
msec = bfd_get_section_by_name (abfd, ".mdebug");
if (msec != NULL)
mips_elf_tdata (abfd)->find_line_info = fi;
/* Note that we don't bother to ever free this information.
- find_nearest_line is either called all the time, as in
- objdump -l, so the information should be saved, or it is
- rarely called, as in ld error messages, so the memory
- wasted is unimportant. Still, it would probably be a
- good idea for free_cached_info to throw it away. */
+ find_nearest_line is either called all the time, as in
+ objdump -l, so the information should be saved, or it is
+ rarely called, as in ld error messages, so the memory
+ wasted is unimportant. Still, it would probably be a
+ good idea for free_cached_info to throw it away. */
}
if (_bfd_ecoff_locate_line (abfd, section, offset, &fi->d, swap,
switch (r)
{
case bfd_reloc_undefined:
- if (!((*link_info->callbacks->undefined_symbol)
- (link_info, bfd_asymbol_name (*(*parent)->sym_ptr_ptr),
- input_bfd, input_section, (*parent)->address, TRUE)))
- goto error_return;
+ (*link_info->callbacks->undefined_symbol)
+ (link_info, bfd_asymbol_name (*(*parent)->sym_ptr_ptr),
+ input_bfd, input_section, (*parent)->address, TRUE);
break;
case bfd_reloc_dangerous:
BFD_ASSERT (error_message != NULL);
- if (!((*link_info->callbacks->reloc_dangerous)
- (link_info, error_message, input_bfd, input_section,
- (*parent)->address)))
- goto error_return;
+ (*link_info->callbacks->reloc_dangerous)
+ (link_info, error_message,
+ input_bfd, input_section, (*parent)->address);
break;
case bfd_reloc_overflow:
- if (!((*link_info->callbacks->reloc_overflow)
- (link_info, NULL,
- bfd_asymbol_name (*(*parent)->sym_ptr_ptr),
- (*parent)->howto->name, (*parent)->addend,
- input_bfd, input_section, (*parent)->address)))
- goto error_return;
+ (*link_info->callbacks->reloc_overflow)
+ (link_info, NULL,
+ bfd_asymbol_name (*(*parent)->sym_ptr_ptr),
+ (*parent)->howto->name, (*parent)->addend,
+ input_bfd, input_section, (*parent)->address);
break;
case bfd_reloc_outofrange:
default:
int fndopc;
/* The number of bytes to delete for relaxation and from where
- to delete these bytes starting at irel->r_offset. */
+ 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. */
+ this reloc. */
if (r_type != R_MICROMIPS_HI16
&& r_type != R_MICROMIPS_PC16_S1
&& r_type != R_MICROMIPS_26_S1)
/* 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. */
+ 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)
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. */
+ 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
+ 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))
+ (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). */
+ 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;
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. */
+ 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);
}
/* 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. */
+ 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
}
/* R_MICROMIPS_PC16_S1 relaxation to R_MICROMIPS_PC10_S1. We need
- to check the distance from the next instruction, so subtract 2. */
+ to check the distance from the next instruction, so subtract 2. */
else if (!insn32
&& r_type == R_MICROMIPS_PC16_S1
&& IS_BITSIZE (pcrval - 2, 11)
}
/* R_MICROMIPS_PC16_S1 relaxation to R_MICROMIPS_PC7_S1. We need
- to check the distance from the next instruction, so subtract 2. */
+ to check the distance from the next instruction, so subtract 2. */
else if (!insn32
&& r_type == R_MICROMIPS_PC16_S1
&& IS_BITSIZE (pcrval - 2, 8)
if (relaxed)
{
/* JAL with 32-bit delay slot that is changed to a JALS
- with 16-bit delay slot. */
+ with 16-bit delay slot. */
bfd_put_micromips_32 (abfd, jal_insn_32_bd16.match, ptr);
/* Delete 2 bytes from irel->r_offset + 6. */
}
/* A function that the linker calls to select between all or only
- 32-bit microMIPS instructions. */
+ 32-bit microMIPS instructions, and between making or ignoring
+ branch relocation checks for invalid transitions between ISA modes.
+ Also record whether we have been configured for a GNU target. */
void
-_bfd_mips_elf_insn32 (struct bfd_link_info *info, bfd_boolean on)
+_bfd_mips_elf_linker_flags (struct bfd_link_info *info, bfd_boolean insn32,
+ bfd_boolean ignore_branch_isa,
+ bfd_boolean gnu_target)
{
- mips_elf_hash_table (info)->insn32 = on;
+ mips_elf_hash_table (info)->insn32 = insn32;
+ mips_elf_hash_table (info)->ignore_branch_isa = ignore_branch_isa;
+ mips_elf_hash_table (info)->gnu_target = gnu_target;
}
\f
/* Structure for saying that BFD machine EXTENSION extends BASE. */
{ bfd_mach_mips_octeon2, bfd_mach_mips_octeonp },
{ bfd_mach_mips_octeonp, bfd_mach_mips_octeon },
{ bfd_mach_mips_octeon, bfd_mach_mipsisa64r2 },
- { bfd_mach_mips_loongson_3a, bfd_mach_mipsisa64r2 },
+ { bfd_mach_mips_gs264e, bfd_mach_mips_gs464e },
+ { bfd_mach_mips_gs464e, bfd_mach_mips_gs464 },
+ { bfd_mach_mips_gs464, bfd_mach_mipsisa64r2 },
/* MIPS64 extensions. */
{ bfd_mach_mipsisa64r2, bfd_mach_mipsisa64 },
{ bfd_mach_mips4400, bfd_mach_mips4000 },
{ bfd_mach_mips4300, bfd_mach_mips4000 },
{ bfd_mach_mips4100, bfd_mach_mips4000 },
- { bfd_mach_mips4010, bfd_mach_mips4000 },
{ bfd_mach_mips5900, bfd_mach_mips4000 },
+ /* MIPS32r3 extensions. */
+ { bfd_mach_mips_interaptiv_mr2, bfd_mach_mipsisa32r3 },
+
+ /* MIPS32r2 extensions. */
+ { bfd_mach_mipsisa32r3, bfd_mach_mipsisa32r2 },
+
/* MIPS32 extensions. */
{ bfd_mach_mipsisa32r2, bfd_mach_mipsisa32 },
/* MIPS II extensions. */
{ bfd_mach_mips4000, bfd_mach_mips6000 },
{ bfd_mach_mipsisa32, bfd_mach_mips6000 },
+ { bfd_mach_mips4010, bfd_mach_mips6000 },
/* MIPS I extensions. */
{ bfd_mach_mips6000, bfd_mach_mips3000 },
{
switch (isa_ext)
{
- case AFL_EXT_3900: return bfd_mach_mips3900;
- case AFL_EXT_4010: return bfd_mach_mips4010;
- case AFL_EXT_4100: return bfd_mach_mips4100;
- case AFL_EXT_4111: return bfd_mach_mips4111;
- case AFL_EXT_4120: return bfd_mach_mips4120;
- case AFL_EXT_4650: return bfd_mach_mips4650;
- case AFL_EXT_5400: return bfd_mach_mips5400;
- case AFL_EXT_5500: return bfd_mach_mips5500;
- case AFL_EXT_5900: return bfd_mach_mips5900;
- case AFL_EXT_10000: return bfd_mach_mips10000;
+ case AFL_EXT_3900: return bfd_mach_mips3900;
+ case AFL_EXT_4010: return bfd_mach_mips4010;
+ case AFL_EXT_4100: return bfd_mach_mips4100;
+ case AFL_EXT_4111: return bfd_mach_mips4111;
+ case AFL_EXT_4120: return bfd_mach_mips4120;
+ case AFL_EXT_4650: return bfd_mach_mips4650;
+ case AFL_EXT_5400: return bfd_mach_mips5400;
+ case AFL_EXT_5500: return bfd_mach_mips5500;
+ case AFL_EXT_5900: return bfd_mach_mips5900;
+ case AFL_EXT_10000: return bfd_mach_mips10000;
case AFL_EXT_LOONGSON_2E: return bfd_mach_mips_loongson_2e;
case AFL_EXT_LOONGSON_2F: return bfd_mach_mips_loongson_2f;
- case AFL_EXT_LOONGSON_3A: return bfd_mach_mips_loongson_3a;
- case AFL_EXT_SB1: return bfd_mach_mips_sb1;
+ case AFL_EXT_SB1: return bfd_mach_mips_sb1;
case AFL_EXT_OCTEON: return bfd_mach_mips_octeon;
case AFL_EXT_OCTEONP: return bfd_mach_mips_octeonp;
case AFL_EXT_OCTEON2: return bfd_mach_mips_octeon2;
- case AFL_EXT_XLR: return bfd_mach_mips_xlr;
- default: return bfd_mach_mips3000;
+ case AFL_EXT_XLR: return bfd_mach_mips_xlr;
+ default: return bfd_mach_mips3000;
}
}
{
switch (bfd_get_mach (abfd))
{
- case bfd_mach_mips3900: return AFL_EXT_3900;
- case bfd_mach_mips4010: return AFL_EXT_4010;
- case bfd_mach_mips4100: return AFL_EXT_4100;
- case bfd_mach_mips4111: return AFL_EXT_4111;
- case bfd_mach_mips4120: return AFL_EXT_4120;
- case bfd_mach_mips4650: return AFL_EXT_4650;
- case bfd_mach_mips5400: return AFL_EXT_5400;
- case bfd_mach_mips5500: return AFL_EXT_5500;
- case bfd_mach_mips5900: return AFL_EXT_5900;
- case bfd_mach_mips10000: return AFL_EXT_10000;
+ case bfd_mach_mips3900: return AFL_EXT_3900;
+ case bfd_mach_mips4010: return AFL_EXT_4010;
+ case bfd_mach_mips4100: return AFL_EXT_4100;
+ case bfd_mach_mips4111: return AFL_EXT_4111;
+ case bfd_mach_mips4120: return AFL_EXT_4120;
+ case bfd_mach_mips4650: return AFL_EXT_4650;
+ case bfd_mach_mips5400: return AFL_EXT_5400;
+ case bfd_mach_mips5500: return AFL_EXT_5500;
+ case bfd_mach_mips5900: return AFL_EXT_5900;
+ case bfd_mach_mips10000: return AFL_EXT_10000;
case bfd_mach_mips_loongson_2e: return AFL_EXT_LOONGSON_2E;
case bfd_mach_mips_loongson_2f: return AFL_EXT_LOONGSON_2F;
- case bfd_mach_mips_loongson_3a: return AFL_EXT_LOONGSON_3A;
- case bfd_mach_mips_sb1: return AFL_EXT_SB1;
- case bfd_mach_mips_octeon: return AFL_EXT_OCTEON;
- case bfd_mach_mips_octeonp: return AFL_EXT_OCTEONP;
- case bfd_mach_mips_octeon3: return AFL_EXT_OCTEON3;
- case bfd_mach_mips_octeon2: return AFL_EXT_OCTEON2;
- case bfd_mach_mips_xlr: return AFL_EXT_XLR;
- default: return 0;
+ case bfd_mach_mips_sb1: return AFL_EXT_SB1;
+ case bfd_mach_mips_octeon: return AFL_EXT_OCTEON;
+ case bfd_mach_mips_octeonp: return AFL_EXT_OCTEONP;
+ case bfd_mach_mips_octeon3: return AFL_EXT_OCTEON3;
+ case bfd_mach_mips_octeon2: return AFL_EXT_OCTEON2;
+ case bfd_mach_mips_xlr: return AFL_EXT_XLR;
+ case bfd_mach_mips_interaptiv_mr2:
+ return AFL_EXT_INTERAPTIV_MR2;
+ default: return 0;
}
}
case E_MIPS_ARCH_64R2: new_isa = LEVEL_REV (64, 2); break;
case E_MIPS_ARCH_64R6: new_isa = LEVEL_REV (64, 6); break;
default:
- (*_bfd_error_handler)
- (_("%B: Unknown architecture %s"),
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: unknown architecture %s"),
abfd, bfd_printable_name (abfd));
}
&& abiflags->fp_abi != Val_GNU_MIPS_ABI_FP_SOFT
&& abiflags->fp_abi != Val_GNU_MIPS_ABI_FP_64A
&& abiflags->isa_level >= 32
- && abiflags->isa_ext != AFL_EXT_LOONGSON_3A)
+ && abiflags->ases != AFL_ASE_LOONGSON_EXT)
abiflags->flags1 |= AFL_FLAGS1_ODDSPREG;
}
scRData, scSData, scSBss, scBss
};
- /* Sort the dynamic symbols so that those with GOT entries come after
- those without. */
htab = mips_elf_hash_table (info);
BFD_ASSERT (htab != NULL);
+ /* Sort the dynamic symbols so that those with GOT entries come after
+ those without. */
if (!mips_elf_sort_hash_table (abfd, info))
return FALSE;
bfd *input_bfd;
Elf32_External_RegInfo ext;
Elf32_RegInfo sub;
+ bfd_size_type sz;
if (p->type != bfd_indirect_link_order)
{
input_section = p->u.indirect.section;
input_bfd = input_section->owner;
+ sz = (input_section->size < sizeof (ext)
+ ? input_section->size : sizeof (ext));
+ memset (&ext, 0, sizeof (ext));
if (! bfd_get_section_contents (input_bfd, input_section,
- &ext, 0, sizeof ext))
+ &ext, 0, sz))
return FALSE;
bfd_mips_elf32_swap_reginfo_in (input_bfd, &ext, &sub);
reginfo.ri_cprmask[3] |= sub.ri_cprmask[3];
/* ri_gp_value is set by the function
- mips_elf32_section_processing when the section is
+ `_bfd_mips_elf_section_processing' when the section is
finally written out. */
/* Hack: reset the SEC_HAS_CONTENTS flag so that
gptab_bss_sec = o;
else
{
- (*_bfd_error_handler)
- (_("%s: illegal section name `%s'"),
- bfd_get_filename (abfd), o->name);
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: illegal section name `%pA'"), abfd, o);
bfd_set_error (bfd_error_nonrepresentable_section);
return FALSE;
}
if there are conflicting settings. */
static bfd_boolean
-mips_elf_merge_obj_e_flags (bfd *ibfd, bfd *obfd)
+mips_elf_merge_obj_e_flags (bfd *ibfd, struct bfd_link_info *info)
{
+ bfd *obfd = info->output_bfd;
struct mips_elf_obj_tdata *out_tdata = mips_elf_tdata (obfd);
flagword old_flags;
flagword new_flags;
if (((new_flags & (EF_MIPS_PIC | EF_MIPS_CPIC)) != 0)
!= ((old_flags & (EF_MIPS_PIC | EF_MIPS_CPIC)) != 0))
{
- (*_bfd_error_handler)
- (_("%B: warning: linking abicalls files with non-abicalls files"),
+ _bfd_error_handler
+ (_("%pB: warning: linking abicalls files with non-abicalls files"),
ibfd);
ok = TRUE;
}
/* Compare the ISAs. */
if (mips_32bit_flags_p (old_flags) != mips_32bit_flags_p (new_flags))
{
- (*_bfd_error_handler)
- (_("%B: linking 32-bit code with 64-bit code"),
+ _bfd_error_handler
+ (_("%pB: linking 32-bit code with 64-bit code"),
ibfd);
ok = FALSE;
}
else
{
/* The ISAs aren't compatible. */
- (*_bfd_error_handler)
- (_("%B: linking %s module with previous %s modules"),
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: linking %s module with previous %s modules"),
ibfd,
bfd_printable_name (ibfd),
bfd_printable_name (obfd));
|| (elf_elfheader (ibfd)->e_ident[EI_CLASS]
!= elf_elfheader (obfd)->e_ident[EI_CLASS]))
{
- (*_bfd_error_handler)
- (_("%B: ABI mismatch: linking %s module with previous %s modules"),
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: ABI mismatch: linking %s module with previous %s modules"),
ibfd,
elf_mips_abi_name (ibfd),
elf_mips_abi_name (obfd));
if (m16_mis || micro_mis)
{
- (*_bfd_error_handler)
- (_("%B: ASE mismatch: linking %s module with previous %s modules"),
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: ASE mismatch: linking %s module with previous %s modules"),
ibfd,
m16_mis ? "MIPS16" : "microMIPS",
m16_mis ? "microMIPS" : "MIPS16");
/* Compare NaN encodings. */
if ((new_flags & EF_MIPS_NAN2008) != (old_flags & EF_MIPS_NAN2008))
{
- _bfd_error_handler (_("%B: linking %s module with previous %s modules"),
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%pB: linking %s module with previous %s modules"),
ibfd,
(new_flags & EF_MIPS_NAN2008
? "-mnan=2008" : "-mnan=legacy"),
/* Compare FP64 state. */
if ((new_flags & EF_MIPS_FP64) != (old_flags & EF_MIPS_FP64))
{
- _bfd_error_handler (_("%B: linking %s module with previous %s modules"),
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%pB: linking %s module with previous %s modules"),
ibfd,
(new_flags & EF_MIPS_FP64
? "-mfp64" : "-mfp32"),
/* Warn about any other mismatches */
if (new_flags != old_flags)
{
- (*_bfd_error_handler)
- (_("%B: uses different e_flags (0x%lx) fields than previous modules "
- "(0x%lx)"),
- ibfd, (unsigned long) new_flags,
- (unsigned long) old_flags);
+ /* xgettext:c-format */
+ _bfd_error_handler
+ (_("%pB: uses different e_flags (%#x) fields than previous modules "
+ "(%#x)"),
+ ibfd, new_flags, old_flags);
ok = FALSE;
}
/* Merge object attributes from IBFD into OBFD. Raise an error if
there are conflicting attributes. */
static bfd_boolean
-mips_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd)
+mips_elf_merge_obj_attributes (bfd *ibfd, struct bfd_link_info *info)
{
+ bfd *obfd = info->output_bfd;
obj_attribute *in_attr;
obj_attribute *out_attr;
bfd *abi_fp_bfd;
in_string = _bfd_mips_fp_abi_string (in_fp);
/* First warn about cases involving unrecognised ABIs. */
if (!out_string && !in_string)
+ /* xgettext:c-format */
_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_fp, in_fp);
+ (_("warning: %pB uses unknown floating point ABI %d "
+ "(set by %pB), %pB uses unknown floating point ABI %d"),
+ obfd, out_fp, abi_fp_bfd, ibfd, in_fp);
else if (!out_string)
_bfd_error_handler
- (_("Warning: %B uses unknown floating point ABI %d "
- "(set by %B), %B uses %s"),
- obfd, abi_fp_bfd, ibfd, out_fp, in_string);
+ /* xgettext:c-format */
+ (_("warning: %pB uses unknown floating point ABI %d "
+ "(set by %pB), %pB uses %s"),
+ obfd, out_fp, abi_fp_bfd, ibfd, in_string);
else if (!in_string)
_bfd_error_handler
- (_("Warning: %B uses %s (set by %B), "
- "%B uses unknown floating point ABI %d"),
- obfd, abi_fp_bfd, ibfd, out_string, in_fp);
+ /* xgettext:c-format */
+ (_("warning: %pB uses %s (set by %pB), "
+ "%pB uses unknown floating point ABI %d"),
+ obfd, out_string, abi_fp_bfd, ibfd, in_fp);
else
{
/* If one of the bfds is soft-float, the other must be
else if (out_fp == Val_GNU_MIPS_ABI_FP_SOFT)
in_string = "-mhard-float";
_bfd_error_handler
- (_("Warning: %B uses %s (set by %B), %B uses %s"),
- obfd, abi_fp_bfd, ibfd, out_string, in_string);
+ /* xgettext:c-format */
+ (_("warning: %pB uses %s (set by %pB), %pB uses %s"),
+ obfd, out_string, abi_fp_bfd, ibfd, in_string);
}
}
}
{
case Val_GNU_MIPS_ABI_MSA_128:
_bfd_error_handler
- (_("Warning: %B uses %s (set by %B), "
- "%B uses unknown MSA ABI %d"),
- obfd, abi_msa_bfd, ibfd,
- "-mmsa", in_attr[Tag_GNU_MIPS_ABI_MSA].i);
+ /* xgettext:c-format */
+ (_("warning: %pB uses %s (set by %pB), "
+ "%pB uses unknown MSA ABI %d"),
+ obfd, "-mmsa", abi_msa_bfd,
+ ibfd, in_attr[Tag_GNU_MIPS_ABI_MSA].i);
break;
default:
{
case Val_GNU_MIPS_ABI_MSA_128:
_bfd_error_handler
- (_("Warning: %B uses unknown MSA ABI %d "
- "(set by %B), %B uses %s"),
- obfd, abi_msa_bfd, ibfd,
- out_attr[Tag_GNU_MIPS_ABI_MSA].i, "-mmsa");
+ /* xgettext:c-format */
+ (_("warning: %pB uses unknown MSA ABI %d "
+ "(set by %pB), %pB uses %s"),
+ obfd, out_attr[Tag_GNU_MIPS_ABI_MSA].i,
+ abi_msa_bfd, ibfd, "-mmsa");
break;
default:
_bfd_error_handler
- (_("Warning: %B uses unknown MSA ABI %d "
- "(set by %B), %B uses unknown MSA ABI %d"),
- obfd, abi_msa_bfd, ibfd,
- out_attr[Tag_GNU_MIPS_ABI_MSA].i,
- in_attr[Tag_GNU_MIPS_ABI_MSA].i);
+ /* xgettext:c-format */
+ (_("warning: %pB uses unknown MSA ABI %d "
+ "(set by %pB), %pB uses unknown MSA ABI %d"),
+ obfd, out_attr[Tag_GNU_MIPS_ABI_MSA].i,
+ abi_msa_bfd, ibfd, in_attr[Tag_GNU_MIPS_ABI_MSA].i);
break;
}
}
}
/* Merge Tag_compatibility attributes and any common GNU ones. */
- return _bfd_elf_merge_object_attributes (ibfd, obfd);
+ return _bfd_elf_merge_object_attributes (ibfd, info);
}
/* Merge object ABI flags from IBFD into OBFD. Raise an error if
object file when linking. */
bfd_boolean
-_bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
+_bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
{
+ bfd *obfd = info->output_bfd;
struct mips_elf_obj_tdata *out_tdata;
struct mips_elf_obj_tdata *in_tdata;
bfd_boolean null_input_bfd = TRUE;
bfd_boolean ok;
/* Check if we have the same endianness. */
- if (! _bfd_generic_verify_endian_match (ibfd, obfd))
+ if (! _bfd_generic_verify_endian_match (ibfd, info))
{
- (*_bfd_error_handler)
- (_("%B: endianness incompatible with that of the selected emulation"),
+ _bfd_error_handler
+ (_("%pB: endianness incompatible with that of the selected emulation"),
ibfd);
return FALSE;
}
if (strcmp (bfd_get_target (ibfd), bfd_get_target (obfd)) != 0)
{
- (*_bfd_error_handler)
- (_("%B: ABI is incompatible with that of the selected emulation"),
+ _bfd_error_handler
+ (_("%pB: ABI is incompatible with that of the selected emulation"),
ibfd);
return FALSE;
}
Elf_Internal_ABIFlags_v0 abiflags;
/* Set up the FP ABI attribute from the abiflags if it is not already
- set. */
+ set. */
if (in_attr[Tag_GNU_MIPS_ABI_FP].i == Val_GNU_MIPS_ABI_FP_ANY)
- in_attr[Tag_GNU_MIPS_ABI_FP].i = in_tdata->abiflags.fp_abi;
+ in_attr[Tag_GNU_MIPS_ABI_FP].i = in_tdata->abiflags.fp_abi;
infer_mips_abiflags (ibfd, &abiflags);
in_abiflags = in_tdata->abiflags;
/* It is not possible to infer the correct ISA revision
- for R3 or R5 so drop down to R2 for the checks. */
+ for R3 or R5 so drop down to R2 for the checks. */
if (in_abiflags.isa_rev == 3 || in_abiflags.isa_rev == 5)
in_abiflags.isa_rev = 2;
if (LEVEL_REV (in_abiflags.isa_level, in_abiflags.isa_rev)
< LEVEL_REV (abiflags.isa_level, abiflags.isa_rev))
- (*_bfd_error_handler)
- (_("%B: warning: Inconsistent ISA between e_flags and "
+ _bfd_error_handler
+ (_("%pB: warning: inconsistent ISA between e_flags and "
".MIPS.abiflags"), ibfd);
if (abiflags.fp_abi != Val_GNU_MIPS_ABI_FP_ANY
&& in_abiflags.fp_abi != abiflags.fp_abi)
- (*_bfd_error_handler)
- (_("%B: warning: Inconsistent FP ABI between .gnu.attributes and "
+ _bfd_error_handler
+ (_("%pB: warning: inconsistent FP ABI between .gnu.attributes and "
".MIPS.abiflags"), ibfd);
if ((in_abiflags.ases & abiflags.ases) != abiflags.ases)
- (*_bfd_error_handler)
- (_("%B: warning: Inconsistent ASEs between e_flags and "
+ _bfd_error_handler
+ (_("%pB: warning: inconsistent ASEs between e_flags and "
".MIPS.abiflags"), ibfd);
/* The isa_ext is allowed to be an extension of what can be inferred
from e_flags. */
if (!mips_mach_extends_p (bfd_mips_isa_ext_mach (abiflags.isa_ext),
bfd_mips_isa_ext_mach (in_abiflags.isa_ext)))
- (*_bfd_error_handler)
- (_("%B: warning: Inconsistent ISA extensions between e_flags and "
+ _bfd_error_handler
+ (_("%pB: warning: inconsistent ISA extensions between e_flags and "
".MIPS.abiflags"), ibfd);
if (in_abiflags.flags2 != 0)
- (*_bfd_error_handler)
- (_("%B: warning: Unexpected flag in the flags2 field of "
+ _bfd_error_handler
+ (_("%pB: warning: unexpected flag in the flags2 field of "
".MIPS.abiflags (0x%lx)"), ibfd,
- (unsigned long) in_abiflags.flags2);
+ in_abiflags.flags2);
}
else
{
ok = TRUE;
}
else
- ok = mips_elf_merge_obj_e_flags (ibfd, obfd);
+ ok = mips_elf_merge_obj_e_flags (ibfd, info);
- ok = mips_elf_merge_obj_attributes (ibfd, obfd) && ok;
+ ok = mips_elf_merge_obj_attributes (ibfd, info) && ok;
ok = mips_elf_merge_obj_abiflags (ibfd, obfd) && ok;
fputs ("\n\tMICROMIPS ASE", file);
if (mask & AFL_ASE_XPA)
fputs ("\n\tXPA ASE", file);
+ if (mask & AFL_ASE_MIPS16E2)
+ fputs ("\n\tMIPS16e2 ASE", file);
+ if (mask & AFL_ASE_CRC)
+ fputs ("\n\tCRC ASE", file);
+ if (mask & AFL_ASE_GINV)
+ fputs ("\n\tGINV ASE", file);
+ if (mask & AFL_ASE_LOONGSON_MMI)
+ fputs ("\n\tLoongson MMI ASE", file);
+ if (mask & AFL_ASE_LOONGSON_CAM)
+ fputs ("\n\tLoongson CAM ASE", file);
+ if (mask & AFL_ASE_LOONGSON_EXT)
+ fputs ("\n\tLoongson EXT ASE", file);
+ if (mask & AFL_ASE_LOONGSON_EXT2)
+ fputs ("\n\tLoongson EXT2 ASE", file);
if (mask == 0)
fprintf (file, "\n\t%s", _("None"));
else if ((mask & ~AFL_ASE_MASK) != 0)
case AFL_EXT_OCTEONP:
fputs ("Cavium Networks OcteonP", file);
break;
- case AFL_EXT_LOONGSON_3A:
- fputs ("Loongson 3A", file);
- break;
case AFL_EXT_OCTEON:
fputs ("Cavium Networks Octeon", file);
break;
case AFL_EXT_LOONGSON_2F:
fputs ("ST Microelectronics Loongson 2F", file);
break;
+ case AFL_EXT_INTERAPTIV_MR2:
+ fputs ("Imagination interAptiv MR2", file);
+ break;
default:
fprintf (file, "%s (%d)", _("Unknown"), isa_ext);
break;
const struct bfd_elf_special_section _bfd_mips_elf_special_sections[] =
{
- { STRING_COMMA_LEN (".lit4"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL },
- { STRING_COMMA_LEN (".lit8"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL },
+ { STRING_COMMA_LEN (".lit4"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL },
+ { STRING_COMMA_LEN (".lit8"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL },
{ STRING_COMMA_LEN (".mdebug"), 0, SHT_MIPS_DEBUG, 0 },
- { STRING_COMMA_LEN (".sbss"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL },
+ { STRING_COMMA_LEN (".sbss"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL },
{ STRING_COMMA_LEN (".sdata"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL },
{ STRING_COMMA_LEN (".ucode"), 0, SHT_MIPS_UCODE, 0 },
- { NULL, 0, 0, 0, 0 }
+ { NULL, 0, 0, 0, 0 }
};
/* Merge non visibility st_other attributes. Ensure that the
return n;
}
+/* Return the ABI flags associated with ABFD if available. */
+
+Elf_Internal_ABIFlags_v0 *
+bfd_mips_elf_get_abiflags (bfd *abfd)
+{
+ struct mips_elf_obj_tdata *tdata = mips_elf_tdata (abfd);
+
+ return tdata->abiflags_valid ? &tdata->abiflags : NULL;
+}
+
+/* MIPS libc ABI versions, used with the EI_ABIVERSION ELF file header
+ field. Taken from `libc-abis.h' generated at GNU libc build time.
+ Using a MIPS_ prefix as other libc targets use different values. */
+enum
+{
+ MIPS_LIBC_ABI_DEFAULT = 0,
+ MIPS_LIBC_ABI_MIPS_PLT,
+ MIPS_LIBC_ABI_UNIQUE,
+ MIPS_LIBC_ABI_MIPS_O32_FP64,
+ MIPS_LIBC_ABI_ABSOLUTE,
+ MIPS_LIBC_ABI_MAX
+};
+
void
_bfd_mips_post_process_headers (bfd *abfd, struct bfd_link_info *link_info)
{
- struct mips_elf_link_hash_table *htab;
+ struct mips_elf_link_hash_table *htab = NULL;
Elf_Internal_Ehdr *i_ehdrp;
i_ehdrp = elf_elfheader (abfd);
{
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;
}
- _bfd_elf_post_process_headers (abfd, link_info);
+ if (htab != NULL && htab->use_plts_and_copy_relocs && !htab->is_vxworks)
+ i_ehdrp->e_ident[EI_ABIVERSION] = MIPS_LIBC_ABI_MIPS_PLT;
if (mips_elf_tdata (abfd)->abiflags.fp_abi == Val_GNU_MIPS_ABI_FP_64
|| mips_elf_tdata (abfd)->abiflags.fp_abi == Val_GNU_MIPS_ABI_FP_64A)
- i_ehdrp->e_ident[EI_ABIVERSION] = 3;
+ i_ehdrp->e_ident[EI_ABIVERSION] = MIPS_LIBC_ABI_MIPS_O32_FP64;
+
+ /* Mark that we need support for absolute symbols in the dynamic loader. */
+ if (htab != NULL && htab->use_absolute_zero && htab->gnu_target)
+ i_ehdrp->e_ident[EI_ABIVERSION] = MIPS_LIBC_ABI_ABSOLUTE;
- if (elf_stack_flags (abfd) && !(elf_stack_flags (abfd) & PF_X))
- i_ehdrp->e_ident[EI_ABIVERSION] = 5;
+ _bfd_elf_post_process_headers (abfd, link_info);
}
int
-_bfd_mips_elf_compact_eh_encoding (struct bfd_link_info *link_info ATTRIBUTE_UNUSED)
+_bfd_mips_elf_compact_eh_encoding
+ (struct bfd_link_info *link_info ATTRIBUTE_UNUSED)
{
return DW_EH_PE_pcrel | DW_EH_PE_sdata4;
}
/* Return the opcode for can't unwind. */
int
-_bfd_mips_elf_cant_unwind_opcode (struct bfd_link_info *link_info ATTRIBUTE_UNUSED)
+_bfd_mips_elf_cant_unwind_opcode
+ (struct bfd_link_info *link_info ATTRIBUTE_UNUSED)
{
return COMPACT_EH_CANT_UNWIND_OPCODE;
}