This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
/* This file handles functionality common to the different MIPS ABI's. */
bfd_vma rld_value;
/* This is set if we see any mips16 stub sections. */
bfd_boolean mips16_stubs_seen;
+ /* True if we've computed the size of the GOT. */
+ bfd_boolean computed_got_sizes;
/* 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;
/* Shortcuts to some dynamic sections, or NULL if they are not
being used. */
asection *srelbss;
memcpy (*loc, &entry, sizeof entry);
- if (g->assigned_gotno >= g->local_gotno)
+ if (g->assigned_gotno > g->local_gotno)
{
(*loc)->gotidx = -1;
/* We didn't allocate enough space in the GOT. */
if (h->got.offset != MINUS_ONE)
return TRUE;
- /* By setting this to a value other than -1, we are indicating that
- there needs to be a GOT entry for H. Avoid using zero, as the
- generic ELF copy_indirect_symbol tests for <= 0. */
if (tls_flag == 0)
- h->got.offset = 1;
+ {
+ /* By setting this to a value other than -1, we are indicating that
+ there needs to be a GOT entry for H. Avoid using zero, as the
+ generic ELF copy_indirect_symbol tests for <= 0. */
+ h->got.offset = 1;
+ if (h->forced_local)
+ g->local_gotno++;
+ }
return TRUE;
}
struct mips_got_entry *entry = (struct mips_got_entry *)*entryp;
struct mips_got_info *g = p;
bfd_vma next_index;
+ unsigned char tls_type;
/* We're only interested in TLS symbols. */
if (entry->tls_type == 0)
return 1;
entry->d.h->tls_type |= GOT_TLS_OFFSET_DONE;
entry->d.h->tls_got_offset = next_index;
+ tls_type = entry->d.h->tls_type;
}
else
{
g->tls_ldm_offset = next_index;
}
entry->gotidx = next_index;
+ tls_type = entry->tls_type;
}
/* Account for the entries we've just allocated. */
- if (entry->tls_type & (GOT_TLS_GD | GOT_TLS_LDM))
+ if (tls_type & (GOT_TLS_GD | GOT_TLS_LDM))
g->tls_assigned_gotno += 2;
- if (entry->tls_type & GOT_TLS_IE)
+ if (tls_type & GOT_TLS_IE)
g->tls_assigned_gotno += 1;
return 1;
/* If this is a 16-bit call to a 32- or 64-bit function with a stub, we
need to redirect the call to the stub. */
else if (r_type == R_MIPS16_26 && !info->relocatable
- && h != NULL
- && ((h->call_stub != NULL || h->call_fp_stub != NULL)
+ && ((h != NULL && (h->call_stub != NULL || h->call_fp_stub != NULL))
|| (local_p
&& elf_tdata (input_bfd)->local_call_stubs != NULL
&& elf_tdata (input_bfd)->local_call_stubs[r_symndx] != NULL))
break;
case R_MIPS_TLS_DTPREL_LO16:
+ case R_MIPS_TLS_DTPREL32:
+ case R_MIPS_TLS_DTPREL64:
value = (symbol + addend - dtprel_base (info)) & howto->dst_mask;
break;
/* VxWorks call relocations point the function's .got.plt
entry, which will be allocated by adjust_dynamic_symbol.
Otherwise, this symbol requires a global GOT entry. */
- if (!htab->is_vxworks
+ if ((!htab->is_vxworks || h->forced_local)
&& !mips_elf_record_global_got_symbol (h, abfd, info, g, 0))
return FALSE;
/* This relocation describes which C++ vtable entries are actually
used. Record for later use during GC. */
case R_MIPS_GNU_VTENTRY:
- if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset))
+ BFD_ASSERT (h != NULL);
+ if (h != NULL
+ && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset))
return FALSE;
break;
bfd *dynobj;
struct mips_elf_link_hash_entry *hmips;
struct mips_elf_link_hash_table *htab;
- unsigned int power_of_two;
htab = mips_elf_hash_table (info);
dynobj = elf_hash_table (info)->dynobj;
h->needs_copy = 1;
}
- /* We need to figure out the alignment required for this symbol. */
- power_of_two = bfd_log2 (h->size);
- if (power_of_two > 4)
- power_of_two = 4;
-
- /* Apply the required alignment. */
- htab->sdynbss->size = BFD_ALIGN (htab->sdynbss->size,
- (bfd_size_type) 1 << power_of_two);
- if (power_of_two > bfd_get_section_alignment (dynobj, htab->sdynbss)
- && !bfd_set_section_alignment (dynobj, htab->sdynbss, power_of_two))
- return FALSE;
-
- /* Define the symbol as being at this point in the section. */
- h->root.u.def.section = htab->sdynbss;
- h->root.u.def.value = htab->sdynbss->size;
-
- /* Increment the section size to make room for the symbol. */
- htab->sdynbss->size += h->size;
-
- return TRUE;
+ return _bfd_elf_adjust_dynamic_copy (h, htab->sdynbss);
}
\f
/* Return the number of dynamic section symbols required by OUTPUT_BFD.
g->tls_assigned_gotno = g->global_gotno + g->local_gotno;
htab_traverse (g->got_entries, mips_elf_initialize_tls_index, g);
}
+ htab->computed_got_sizes = TRUE;
return TRUE;
}
;
else
{
+ struct mips_elf_link_hash_table *htab;
+
+ htab = mips_elf_hash_table (info);
BFD_ASSERT (name != NULL);
+ if (!htab->small_data_overflow_reported
+ && (howto->type == R_MIPS_GPREL16
+ || howto->type == R_MIPS_LITERAL))
+ {
+ const char *msg =
+ _("small-data section exceeds 64KB;"
+ " lower small-data size limit (see option -G)");
+
+ 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)))
memset (b - dyn_skipped, 0, dyn_skipped);
}
- if (sgot != NULL && sgot->size > 0)
+ if (sgot != NULL && sgot->size > 0
+ && !bfd_is_abs_section (sgot->output_section))
{
if (htab->is_vxworks)
{
asection *got;
struct mips_got_info *g;
struct mips_elf_link_hash_entry *h;
+ struct mips_elf_link_hash_table *htab;
h = (struct mips_elf_link_hash_entry *) entry;
if (h->forced_local)
h->forced_local = force_local;
dynobj = elf_hash_table (info)->dynobj;
+ htab = mips_elf_hash_table (info);
if (dynobj != NULL && force_local && h->root.type != STT_TLS
&& (got = mips_elf_got_section (dynobj, TRUE)) != NULL
&& (g = mips_elf_section_data (got)->u.got_info) != NULL)
gg->assigned_gotno--;
}
}
- else if (g->global_gotno == 0 && g->global_gotsym == NULL)
- /* If we haven't got through GOT allocation yet, just bump up the
- number of local entries, as this symbol won't be counted as
- global. */
- g->local_gotno++;
else if (h->root.got.offset == 1)
{
- /* If we're past non-multi-GOT allocation and this symbol had
- been marked for a global got entry, give it a local entry
- instead. */
- BFD_ASSERT (g->global_gotno > 0);
+ /* check_relocs didn't know that this symbol would be
+ forced-local, so add an extra local got entry. */
g->local_gotno++;
- g->global_gotno--;
+ if (htab->computed_got_sizes)
+ {
+ /* We'll have treated this symbol as global rather
+ than local. */
+ BFD_ASSERT (g->global_gotno > 0);
+ g->global_gotno--;
+ }
}
+ else if (htab->is_vxworks && h->root.needs_plt)
+ {
+ /* check_relocs didn't know that this symbol would be
+ forced-local, so add an extra local got entry. */
+ g->local_gotno++;
+ if (htab->computed_got_sizes)
+ /* The symbol is only used in call relocations, so we'll
+ have assumed it only needs a .got.plt entry. Increase
+ the size of .got accordingly. */
+ got->size += MIPS_ELF_GOT_SIZE (dynobj);
+ }
}
_bfd_elf_link_hash_hide_symbol (info, &h->root, force_local);
ret->use_rld_obj_head = FALSE;
ret->rld_value = 0;
ret->mips16_stubs_seen = FALSE;
+ ret->computed_got_sizes = FALSE;
ret->is_vxworks = FALSE;
+ ret->small_data_overflow_reported = FALSE;
ret->srelbss = NULL;
ret->sdynbss = NULL;
ret->srelplt = NULL;
}
+/* 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)
+{
+ obj_attribute *in_attr;
+ obj_attribute *out_attr;
+
+ if (!elf_known_obj_attributes_proc (obfd)[0].i)
+ {
+ /* This is the first object. Copy the attributes. */
+ _bfd_elf_copy_obj_attributes (ibfd, obfd);
+
+ /* Use the Tag_null value to indicate the attributes have been
+ initialized. */
+ elf_known_obj_attributes_proc (obfd)[0].i = 1;
+
+ return TRUE;
+ }
+
+ /* Check for conflicting Tag_GNU_MIPS_ABI_FP attributes and merge
+ non-conflicting ones. */
+ in_attr = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU];
+ out_attr = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU];
+ if (in_attr[Tag_GNU_MIPS_ABI_FP].i != out_attr[Tag_GNU_MIPS_ABI_FP].i)
+ {
+ out_attr[Tag_GNU_MIPS_ABI_FP].type = 1;
+ if (out_attr[Tag_GNU_MIPS_ABI_FP].i == 0)
+ out_attr[Tag_GNU_MIPS_ABI_FP].i = in_attr[Tag_GNU_MIPS_ABI_FP].i;
+ else if (in_attr[Tag_GNU_MIPS_ABI_FP].i == 0)
+ ;
+ else if (in_attr[Tag_GNU_MIPS_ABI_FP].i > 3)
+ _bfd_error_handler
+ (_("Warning: %B uses unknown floating point ABI %d"), ibfd,
+ in_attr[Tag_GNU_MIPS_ABI_FP].i);
+ else if (out_attr[Tag_GNU_MIPS_ABI_FP].i > 3)
+ _bfd_error_handler
+ (_("Warning: %B uses unknown floating point ABI %d"), obfd,
+ out_attr[Tag_GNU_MIPS_ABI_FP].i);
+ else
+ switch (out_attr[Tag_GNU_MIPS_ABI_FP].i)
+ {
+ case 1:
+ switch (in_attr[Tag_GNU_MIPS_ABI_FP].i)
+ {
+ case 2:
+ _bfd_error_handler
+ (_("Warning: %B uses -msingle-float, %B uses -mdouble-float"),
+ obfd, ibfd);
+
+ case 3:
+ _bfd_error_handler
+ (_("Warning: %B uses hard float, %B uses soft float"),
+ obfd, ibfd);
+ break;
+
+ default:
+ abort ();
+ }
+ break;
+
+ case 2:
+ switch (in_attr[Tag_GNU_MIPS_ABI_FP].i)
+ {
+ case 1:
+ _bfd_error_handler
+ (_("Warning: %B uses -msingle-float, %B uses -mdouble-float"),
+ ibfd, obfd);
+
+ case 3:
+ _bfd_error_handler
+ (_("Warning: %B uses hard float, %B uses soft float"),
+ obfd, ibfd);
+ break;
+
+ default:
+ abort ();
+ }
+ break;
+
+ case 3:
+ switch (in_attr[Tag_GNU_MIPS_ABI_FP].i)
+ {
+ case 1:
+ case 2:
+ _bfd_error_handler
+ (_("Warning: %B uses hard float, %B uses soft float"),
+ ibfd, obfd);
+ break;
+
+ default:
+ abort ();
+ }
+ break;
+
+ default:
+ abort ();
+ }
+ }
+
+ /* Merge Tag_compatibility attributes and any common GNU ones. */
+ _bfd_elf_merge_object_attributes (ibfd, obfd);
+
+ return TRUE;
+}
+
/* Merge backend specific data from an object file to the output
object file when linking. */
return FALSE;
}
+ if (!mips_elf_merge_obj_attributes (ibfd, obfd))
+ return FALSE;
+
new_flags = elf_elfheader (ibfd)->e_flags;
elf_elfheader (obfd)->e_flags |= new_flags & EF_MIPS_NOREORDER;
old_flags = elf_elfheader (obfd)->e_flags;