/* Input BFD providing Tag_GNU_MIPS_ABI_FP attribute for output. */
bfd *abi_fp_bfd;
+ /* Input BFD providing Tag_GNU_MIPS_ABI_MSA attribute for output. */
+ bfd *abi_msa_bfd;
+
/* The GOT requirements of input bfds. */
struct mips_got_info *got;
/* Record that G requires a page entry that can reach SEC + ADDEND. */
static bfd_boolean
-mips_elf_record_got_page_entry (struct mips_got_info *g,
+mips_elf_record_got_page_entry (struct mips_elf_traverse_got_arg *arg,
asection *sec, bfd_signed_vma addend)
{
+ struct mips_got_info *g = arg->g;
struct mips_got_page_entry lookup, *entry;
struct mips_got_page_range **range_ptr, *range;
bfd_vma old_pages, new_pages;
entry = (struct mips_got_page_entry *) *loc;
if (!entry)
{
- entry = bfd_zalloc (sec->owner, sizeof (*entry));
+ entry = bfd_zalloc (arg->info->output_bfd, sizeof (*entry));
if (!entry)
return FALSE;
range = *range_ptr;
if (!range || addend < range->min_addend - 0xffff)
{
- range = bfd_zalloc (sec->owner, sizeof (*range));
+ range = bfd_zalloc (arg->info->output_bfd, sizeof (*range));
if (!range)
return FALSE;
else
addend = isym->st_value + ref->addend;
}
- if (!mips_elf_record_got_page_entry (arg->g, sec, addend))
+ if (!mips_elf_record_got_page_entry (arg, sec, addend))
{
arg->g = NULL;
return 0;
return TRUE;
}
+/* Return true if a GOT entry for H should live in the local rather than
+ global GOT area. */
+
+static bfd_boolean
+mips_use_local_got_p (struct bfd_link_info *info,
+ struct mips_elf_link_hash_entry *h)
+{
+ /* Symbols that aren't in the dynamic symbol table must live in the
+ local GOT. This includes symbols that are completely undefined
+ and which therefore don't bind locally. We'll report undefined
+ symbols later if appropriate. */
+ if (h->root.dynindx == -1)
+ return TRUE;
+
+ /* 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
+ ? SYMBOL_CALLS_LOCAL (info, &h->root)
+ : SYMBOL_REFERENCES_LOCAL (info, &h->root))
+ return TRUE;
+
+ /* If this is an executable that must provide a definition of the symbol,
+ either though PLTs or copy relocations, then that address should go in
+ the local rather than global GOT. */
+ if (info->executable && h->has_static_relocs)
+ return TRUE;
+
+ return FALSE;
+}
+
/* A mips_elf_link_hash_traverse callback for which DATA points to the
link_info structure. Decide whether the hash entry needs an entry in
the global part of the primary GOT, setting global_got_area accordingly.
if (h->global_got_area != GGA_NONE)
{
/* Make a final decision about whether the symbol belongs in the
- local or global GOT. Symbols that bind locally can (and in the
- case of forced-local symbols, must) live in the local GOT.
- Those that are aren't in the dynamic symbol table must also
- live in the local GOT.
-
- Note that the former condition does not always imply the
- latter: symbols do not bind locally if they are completely
- undefined. We'll report undefined symbols later if appropriate. */
- if (h->root.dynindx == -1
- || (h->got_only_for_calls
- ? SYMBOL_CALLS_LOCAL (info, &h->root)
- : SYMBOL_REFERENCES_LOCAL (info, &h->root)))
+ local or global GOT. */
+ if (mips_use_local_got_p (info, h))
/* The symbol belongs in the local GOT. We no longer need this
entry if it was only used for relocations; those relocations
will be against the null or section symbol instead of H. */
h->non_elf = 0;
h->def_regular = 1;
h->type = STT_OBJECT;
+ h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN;
elf_hash_table (info)->hgot = h;
if (info->shared
&& (target_is_16_bit_code_p
|| target_is_micromips_code_p))));
- local_p = (h == NULL
- || (h->got_only_for_calls
- ? SYMBOL_CALLS_LOCAL (info, &h->root)
- : SYMBOL_REFERENCES_LOCAL (info, &h->root)));
+ local_p = (h == NULL || mips_use_local_got_p (info, h));
gp0 = _bfd_get_gp_value (input_bfd);
gp = _bfd_get_gp_value (abfd);
unsigned int r_type;
struct elf_link_hash_entry *h;
bfd_boolean can_make_dynamic_p;
+ bfd_boolean call_reloc_p;
+ bfd_boolean constrain_symbol_p;
r_symndx = ELF_R_SYM (abfd, rel->r_info);
r_type = ELF_R_TYPE (abfd, rel->r_info);
/* Set CAN_MAKE_DYNAMIC_P to true if we can convert this
relocation into a dynamic one. */
can_make_dynamic_p = FALSE;
+
+ /* Set CALL_RELOC_P to true if the relocation is for a call,
+ and if pointer equality therefore doesn't matter. */
+ call_reloc_p = FALSE;
+
+ /* Set CONSTRAIN_SYMBOL_P if we need to take the relocation
+ into account when deciding how to define the symbol.
+ Relocations in nonallocatable sections such as .pdr and
+ .debug* should have no effect. */
+ constrain_symbol_p = ((sec->flags & SEC_ALLOC) != 0);
+
switch (r_type)
{
- case R_MIPS_GOT16:
case R_MIPS_CALL16:
case R_MIPS_CALL_HI16:
case R_MIPS_CALL_LO16:
+ case R_MIPS16_CALL16:
+ case R_MICROMIPS_CALL16:
+ case R_MICROMIPS_CALL_HI16:
+ case R_MICROMIPS_CALL_LO16:
+ call_reloc_p = TRUE;
+ /* Fall through. */
+
+ case R_MIPS_GOT16:
case R_MIPS_GOT_HI16:
case R_MIPS_GOT_LO16:
case R_MIPS_GOT_PAGE:
case R_MIPS_TLS_GD:
case R_MIPS_TLS_LDM:
case R_MIPS16_GOT16:
- case R_MIPS16_CALL16:
case R_MIPS16_TLS_GOTTPREL:
case R_MIPS16_TLS_GD:
case R_MIPS16_TLS_LDM:
case R_MICROMIPS_GOT16:
- case R_MICROMIPS_CALL16:
- case R_MICROMIPS_CALL_HI16:
- case R_MICROMIPS_CALL_LO16:
case R_MICROMIPS_GOT_HI16:
case R_MICROMIPS_GOT_LO16:
case R_MICROMIPS_GOT_PAGE:
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
+ can_make_dynamic_p = TRUE;
break;
- /* This is just a hint; it can safely be ignored. Don't set
- has_static_relocs for the corresponding symbol. */
+ case R_MIPS_NONE:
case R_MIPS_JALR:
case R_MICROMIPS_JALR:
+ /* These relocations have empty fields and are purely there to
+ provide link information. The symbol value doesn't matter. */
+ constrain_symbol_p = FALSE;
+ break;
+
+ case R_MIPS_GPREL16:
+ case R_MIPS_GPREL32:
+ case R_MIPS16_GPREL:
+ case R_MICROMIPS_GPREL16:
+ /* GP-relative relocations always resolve to a definition in a
+ regular input file, ignoring the one-definition rule. This is
+ important for the GP setup sequence in NewABI code, which
+ always resolves to a local function even if other relocations
+ against the symbol wouldn't. */
+ constrain_symbol_p = FALSE;
break;
case R_MIPS_32:
can_make_dynamic_p = TRUE;
if (dynobj == NULL)
elf_hash_table (info)->dynobj = dynobj = abfd;
- break;
}
- /* For sections that are not SEC_ALLOC a copy reloc would be
- output if possible (implying questionable semantics for
- read-only data objects) or otherwise the final link would
- fail as ld.so will not process them and could not therefore
- handle any outstanding dynamic relocations.
-
- For such sections that are also SEC_DEBUGGING, we can avoid
- these problems by simply ignoring any relocs as these
- sections have a predefined use and we know it is safe to do
- so.
-
- This is needed in cases such as a global symbol definition
- in a shared library causing a common symbol from an object
- file to be converted to an undefined reference. If that
- happens, then all the relocations against this symbol from
- SEC_DEBUGGING sections in the object file will resolve to
- nil. */
- if ((sec->flags & SEC_DEBUGGING) != 0)
- break;
- /* Fall through. */
-
- default:
- /* Most static relocations require pointer equality, except
- for branches. */
- if (h)
- h->pointer_equality_needed = TRUE;
- /* Fall through. */
+ break;
case R_MIPS_26:
case R_MIPS_PC16:
case R_MICROMIPS_PC10_S1:
case R_MICROMIPS_PC16_S1:
case R_MICROMIPS_PC23_S2:
- if (h)
- ((struct mips_elf_link_hash_entry *) h)->has_static_relocs = TRUE;
+ call_reloc_p = TRUE;
break;
}
if (h)
{
+ if (constrain_symbol_p)
+ {
+ if (!can_make_dynamic_p)
+ ((struct mips_elf_link_hash_entry *) h)->has_static_relocs = 1;
+
+ if (!call_reloc_p)
+ h->pointer_equality_needed = 1;
+
+ /* We must not create a stub for a symbol that has
+ relocations related to taking the function's address.
+ This doesn't apply to VxWorks, where CALL relocs refer
+ to a .got.plt entry instead of a normal .got entry. */
+ if (!htab->is_vxworks && (!can_make_dynamic_p || !call_reloc_p))
+ ((struct mips_elf_link_hash_entry *) h)->no_fn_stub = TRUE;
+ }
+
/* Relocations against the special VxWorks __GOTT_BASE__ and
__GOTT_INDEX__ symbols must be left to the loader. Allocate
room for them in .rela.dyn. */
h->plt.plist->need_comp = TRUE;
}
- /* We must not create a stub for a symbol that has relocations
- related to taking the function's address. This doesn't apply to
- VxWorks, where CALL relocs refer to a .got.plt entry instead of
- a normal .got entry. */
- if (!htab->is_vxworks && h != NULL)
- switch (r_type)
- {
- default:
- ((struct mips_elf_link_hash_entry *) h)->no_fn_stub = TRUE;
- break;
- case R_MIPS16_CALL16:
- case R_MIPS_CALL16:
- case R_MIPS_CALL_HI16:
- case R_MIPS_CALL_LO16:
- case R_MIPS_JALR:
- case R_MICROMIPS_CALL16:
- case R_MICROMIPS_CALL_HI16:
- case R_MICROMIPS_CALL_LO16:
- case R_MICROMIPS_JALR:
- break;
- }
-
/* See if this reloc would need to refer to a MIPS16 hard-float stub,
if there is one. We only need to handle global symbols here;
we decide whether to keep or delete stubs for local symbols
obj_attribute *in_attr;
obj_attribute *out_attr;
bfd *abi_fp_bfd;
+ bfd *abi_msa_bfd;
abi_fp_bfd = mips_elf_tdata (obfd)->abi_fp_bfd;
in_attr = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU];
- if (!abi_fp_bfd && in_attr[Tag_GNU_MIPS_ABI_FP].i != 0)
+ if (!abi_fp_bfd && in_attr[Tag_GNU_MIPS_ABI_FP].i != Val_GNU_MIPS_ABI_FP_ANY)
mips_elf_tdata (obfd)->abi_fp_bfd = ibfd;
+ abi_msa_bfd = mips_elf_tdata (obfd)->abi_msa_bfd;
+ if (!abi_msa_bfd
+ && in_attr[Tag_GNU_MIPS_ABI_MSA].i != Val_GNU_MIPS_ABI_MSA_ANY)
+ mips_elf_tdata (obfd)->abi_msa_bfd = ibfd;
+
if (!elf_known_obj_attributes_proc (obfd)[0].i)
{
/* This is the first object. Copy the attributes. */
if (in_attr[Tag_GNU_MIPS_ABI_FP].i != out_attr[Tag_GNU_MIPS_ABI_FP].i)
{
out_attr[Tag_GNU_MIPS_ABI_FP].type = 1;
- if (out_attr[Tag_GNU_MIPS_ABI_FP].i == 0)
+ if (out_attr[Tag_GNU_MIPS_ABI_FP].i == Val_GNU_MIPS_ABI_FP_ANY)
out_attr[Tag_GNU_MIPS_ABI_FP].i = in_attr[Tag_GNU_MIPS_ABI_FP].i;
- else if (in_attr[Tag_GNU_MIPS_ABI_FP].i != 0)
+ else if (in_attr[Tag_GNU_MIPS_ABI_FP].i != Val_GNU_MIPS_ABI_FP_ANY)
switch (out_attr[Tag_GNU_MIPS_ABI_FP].i)
{
- case 1:
+ case Val_GNU_MIPS_ABI_FP_DOUBLE:
switch (in_attr[Tag_GNU_MIPS_ABI_FP].i)
{
- case 2:
+ case Val_GNU_MIPS_ABI_FP_SINGLE:
_bfd_error_handler
(_("Warning: %B uses %s (set by %B), %B uses %s"),
obfd, abi_fp_bfd, ibfd, "-mdouble-float", "-msingle-float");
break;
- case 3:
+ case Val_GNU_MIPS_ABI_FP_SOFT:
_bfd_error_handler
(_("Warning: %B uses %s (set by %B), %B uses %s"),
obfd, abi_fp_bfd, ibfd, "-mhard-float", "-msoft-float");
break;
- case 4:
+ case Val_GNU_MIPS_ABI_FP_64:
_bfd_error_handler
(_("Warning: %B uses %s (set by %B), %B uses %s"),
obfd, abi_fp_bfd, ibfd,
}
break;
- case 2:
+ case Val_GNU_MIPS_ABI_FP_SINGLE:
switch (in_attr[Tag_GNU_MIPS_ABI_FP].i)
{
- case 1:
+ case Val_GNU_MIPS_ABI_FP_DOUBLE:
_bfd_error_handler
(_("Warning: %B uses %s (set by %B), %B uses %s"),
obfd, abi_fp_bfd, ibfd, "-msingle-float", "-mdouble-float");
break;
- case 3:
+ case Val_GNU_MIPS_ABI_FP_SOFT:
_bfd_error_handler
(_("Warning: %B uses %s (set by %B), %B uses %s"),
obfd, abi_fp_bfd, ibfd, "-mhard-float", "-msoft-float");
break;
- case 4:
+ case Val_GNU_MIPS_ABI_FP_64:
_bfd_error_handler
(_("Warning: %B uses %s (set by %B), %B uses %s"),
obfd, abi_fp_bfd, ibfd,
}
break;
- case 3:
+ case Val_GNU_MIPS_ABI_FP_SOFT:
switch (in_attr[Tag_GNU_MIPS_ABI_FP].i)
{
- case 1:
- case 2:
- case 4:
+ case Val_GNU_MIPS_ABI_FP_DOUBLE:
+ case Val_GNU_MIPS_ABI_FP_SINGLE:
+ case Val_GNU_MIPS_ABI_FP_64:
_bfd_error_handler
(_("Warning: %B uses %s (set by %B), %B uses %s"),
obfd, abi_fp_bfd, ibfd, "-msoft-float", "-mhard-float");
}
break;
- case 4:
+ case Val_GNU_MIPS_ABI_FP_64:
switch (in_attr[Tag_GNU_MIPS_ABI_FP].i)
{
- case 1:
+ case Val_GNU_MIPS_ABI_FP_DOUBLE:
_bfd_error_handler
(_("Warning: %B uses %s (set by %B), %B uses %s"),
obfd, abi_fp_bfd, ibfd,
"-mips32r2 -mfp64", "-mdouble-float");
break;
- case 2:
+ case Val_GNU_MIPS_ABI_FP_SINGLE:
_bfd_error_handler
(_("Warning: %B uses %s (set by %B), %B uses %s"),
obfd, abi_fp_bfd, ibfd,
"-mips32r2 -mfp64", "-msingle-float");
break;
- case 3:
+ case Val_GNU_MIPS_ABI_FP_SOFT:
_bfd_error_handler
(_("Warning: %B uses %s (set by %B), %B uses %s"),
obfd, abi_fp_bfd, ibfd, "-mhard-float", "-msoft-float");
default:
switch (in_attr[Tag_GNU_MIPS_ABI_FP].i)
{
- case 1:
+ case Val_GNU_MIPS_ABI_FP_DOUBLE:
_bfd_error_handler
(_("Warning: %B uses unknown floating point ABI %d "
"(set by %B), %B uses %s"),
out_attr[Tag_GNU_MIPS_ABI_FP].i, "-mdouble-float");
break;
- case 2:
+ case Val_GNU_MIPS_ABI_FP_SINGLE:
_bfd_error_handler
(_("Warning: %B uses unknown floating point ABI %d "
"(set by %B), %B uses %s"),
out_attr[Tag_GNU_MIPS_ABI_FP].i, "-msingle-float");
break;
- case 3:
+ case Val_GNU_MIPS_ABI_FP_SOFT:
_bfd_error_handler
(_("Warning: %B uses unknown floating point ABI %d "
"(set by %B), %B uses %s"),
out_attr[Tag_GNU_MIPS_ABI_FP].i, "-msoft-float");
break;
- case 4:
+ case Val_GNU_MIPS_ABI_FP_64:
_bfd_error_handler
(_("Warning: %B uses unknown floating point ABI %d "
"(set by %B), %B uses %s"),
}
}
+ /* Check for conflicting Tag_GNU_MIPS_ABI_MSA attributes and merge
+ non-conflicting ones. */
+ if (in_attr[Tag_GNU_MIPS_ABI_MSA].i != out_attr[Tag_GNU_MIPS_ABI_MSA].i)
+ {
+ out_attr[Tag_GNU_MIPS_ABI_MSA].type = 1;
+ if (out_attr[Tag_GNU_MIPS_ABI_MSA].i == Val_GNU_MIPS_ABI_MSA_ANY)
+ out_attr[Tag_GNU_MIPS_ABI_MSA].i = in_attr[Tag_GNU_MIPS_ABI_MSA].i;
+ else if (in_attr[Tag_GNU_MIPS_ABI_MSA].i != Val_GNU_MIPS_ABI_MSA_ANY)
+ switch (out_attr[Tag_GNU_MIPS_ABI_MSA].i)
+ {
+ 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);
+ break;
+
+ default:
+ switch (in_attr[Tag_GNU_MIPS_ABI_MSA].i)
+ {
+ 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");
+ 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);
+ break;
+ }
+ }
+ }
+
/* Merge Tag_compatibility attributes and any common GNU ones. */
_bfd_elf_merge_object_attributes (ibfd, obfd);
old_flags &= ~ EF_MIPS_ARCH_ASE;
}
+ /* 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"),
+ ibfd,
+ (new_flags & EF_MIPS_NAN2008
+ ? "-mnan=2008" : "-mnan=legacy"),
+ (old_flags & EF_MIPS_NAN2008
+ ? "-mnan=2008" : "-mnan=legacy"));
+ ok = FALSE;
+ new_flags &= ~EF_MIPS_NAN2008;
+ old_flags &= ~EF_MIPS_NAN2008;
+ }
+
/* Warn about any other mismatches */
if (new_flags != old_flags)
{
if (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_MICROMIPS)
fprintf (file, " [micromips]");
+ if (elf_elfheader (abfd)->e_flags & EF_MIPS_NAN2008)
+ fprintf (file, " [nan2008]");
+
+ if (elf_elfheader (abfd)->e_flags & EF_MIPS_FP64)
+ fprintf (file, " [fp64]");
+
if (elf_elfheader (abfd)->e_flags & EF_MIPS_32BITMODE)
fprintf (file, " [32bitmode]");
else
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);
}