/* MIPS-specific support for ELF
Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
- 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+ 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
Most of the information added by Ian Lance Taylor, Cygnus Support,
<ian@cygnus.com>.
(abfd == NULL)
(2) SYMBOL + OFFSET addresses, where SYMBOL is local to an input bfd
(abfd != NULL, symndx >= 0)
- (3) global and forced-local symbols
+ (3) SYMBOL addresses, where SYMBOL is not local to an input bfd
(abfd != NULL, symndx == -1)
Type (3) entries are treated differently for different types of GOT.
that should be added to the symbol value. */
bfd_vma addend;
/* If abfd != NULL && symndx == -1, the hash table entry
- corresponding to a global symbol in the got (or, local, if
- h->forced_local). */
+ corresponding to symbol in the GOT. The symbol's entry
+ is in the local area if h->global_got_area is GGA_NONE,
+ otherwise it is in the global area. */
struct mips_elf_link_hash_entry *h;
} d;
#define is_mips_elf(bfd) \
(bfd_get_flavour (bfd) == bfd_target_elf_flavour \
&& elf_tdata (bfd) != NULL \
- && elf_object_id (bfd) == MIPS_ELF_TDATA)
+ && elf_object_id (bfd) == MIPS_ELF_DATA)
/* The ABI says that every symbol used by dynamic relocations must have
a global GOT entry. Among other things, this provides the dynamic
/* The highest GGA_* value that satisfies all references to this symbol. */
unsigned int global_got_area : 2;
+ /* True if all GOT relocations against this symbol are for calls. This is
+ a looser condition than no_fn_stub below, because there may be other
+ non-call non-GOT relocations against the symbol. */
+ unsigned int got_only_for_calls : 1;
+
/* True if one of the relocations described by possibly_dynamic_relocs
is against a readonly section. */
unsigned int readonly_reloc : 1;
asection *(*add_stub_section) (const char *, asection *, asection *);
};
+/* Get the MIPS ELF linker hash table from a link_info structure. */
+
+#define mips_elf_hash_table(p) \
+ (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \
+ == MIPS_ELF_DATA ? ((struct mips_elf_link_hash_table *) ((p)->hash)) : NULL)
+
/* A structure used to communicate with htab_traverse callbacks. */
-struct mips_htab_traverse_info {
+struct mips_htab_traverse_info
+{
/* The usual link-wide information. */
struct bfd_link_info *info;
bfd *output_bfd;
#define MIPS_ELF_RTYPE_TO_HOWTO(abfd, rtype, rela) \
(get_elf_backend_data (abfd)->elf_backend_mips_rtype_to_howto (rtype, rela))
-/* Determine whether the internal relocation of index REL_IDX is REL
- (zero) or RELA (non-zero). The assumption is that, if there are
- two relocation sections for this section, one of them is REL and
- the other is RELA. If the index of the relocation we're testing is
- in range for the first relocation section, check that the external
- relocation size is that for RELA. It is also assumed that, if
- rel_idx is not in range for the first section, and this first
- section contains REL relocs, then the relocation is in the second
- section, that is RELA. */
-#define MIPS_RELOC_RELA_P(abfd, sec, rel_idx) \
- ((NUM_SHDR_ENTRIES (&elf_section_data (sec)->rel_hdr) \
- * get_elf_backend_data (abfd)->s->int_rels_per_ext_rel \
- > (bfd_vma)(rel_idx)) \
- == (elf_section_data (sec)->rel_hdr.sh_entsize \
- == (ABI_64_P (abfd) ? sizeof (Elf64_External_Rela) \
- : sizeof (Elf32_External_Rela))))
-
/* The name of the dynamic relocation section. */
#define MIPS_ELF_REL_DYN_NAME(INFO) \
(mips_elf_hash_table (INFO)->is_vxworks ? ".rela.dyn" : ".rel.dyn")
(bfd_boolean (*) (struct elf_link_hash_entry *, void *)) (func), \
(info)))
-/* Get the MIPS ELF linker hash table from a link_info structure. */
-
-#define mips_elf_hash_table(p) \
- ((struct mips_elf_link_hash_table *) ((p)->hash))
-
/* Find the base offsets for thread-local storage in this object,
for GD/LD and IE/LE respectively. */
ret->call_fp_stub = NULL;
ret->tls_type = GOT_NORMAL;
ret->global_got_area = GGA_NONE;
+ ret->got_only_for_calls = TRUE;
ret->readonly_reloc = FALSE;
ret->has_static_relocs = FALSE;
ret->no_fn_stub = FALSE;
struct mips_elf_link_hash_table *htab;
htab = mips_elf_hash_table (info);
+ if (htab == NULL)
+ return FALSE;
+
htab->add_stub_section = fn;
htab->la25_stubs = htab_try_create (1, mips_elf_la25_stub_hash,
mips_elf_la25_stub_eq, NULL);
unsigned int align;
htab = mips_elf_hash_table (info);
+ if (htab == NULL)
+ return FALSE;
/* Create a unique name for the new section. */
name = bfd_malloc (11 + sizeof (".text.stub."));
asection *s;
htab = mips_elf_hash_table (info);
+ if (htab == NULL)
+ return FALSE;
/* Create a trampoline section, if we haven't already. */
s = htab->strampoline;
/* See if we've already created an equivalent stub. */
htab = mips_elf_hash_table (info);
+ if (htab == NULL)
+ return FALSE;
+
slot = htab_find_slot (htab->la25_stubs, &search, INSERT);
if (slot == NULL)
return FALSE;
bfd_boolean need_relocs = FALSE;
htab = mips_elf_hash_table (info);
+ if (htab == NULL)
+ return;
+
sgot = htab->sgot;
indx = 0;
struct mips_elf_link_hash_table *htab;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
BFD_ASSERT (h->plt.offset != (bfd_vma) -1);
/* This function only works for VxWorks, because a non-VxWorks .got.plt
struct mips_got_entry *entry;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
entry = mips_elf_create_local_got_entry (abfd, info, ibfd, value,
r_symndx, h, r_type);
if (!entry)
long global_got_dynindx = 0;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
gg = g = htab->got_info;
if (g->bfd2got && ibfd)
{
}
/* Find a local GOT entry for an R_MIPS*_GOT16 relocation against VALUE.
- EXTERNAL is true if the relocation was against a global symbol
- that has been forced local. */
+ EXTERNAL is true if the relocation was originally against a global
+ symbol that binds locally. */
static bfd_vma
mips_elf_got16_entry (bfd *abfd, bfd *ibfd, struct bfd_link_info *info,
bfd_vma gp;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
sgot = htab->sgot;
gp = _bfd_get_gp_value (output_bfd)
+ mips_elf_adjust_gp (output_bfd, htab->got_info, input_bfd);
struct mips_elf_link_hash_table *htab;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
entry.abfd = NULL;
entry.symndx = -1;
BFD_ASSERT (g != NULL);
}
- /* We might have a symbol, H, if it has been forced local. Use the
- global entry then. It doesn't matter whether an entry is local
- or global for TLS, since the dynamic linker does not
- automatically relocate TLS GOT entries. */
- BFD_ASSERT (h == NULL || h->root.forced_local);
+ /* This function shouldn't be called for symbols that live in the global
+ area of the GOT. */
+ BFD_ASSERT (h == NULL || h->global_got_area == GGA_NONE);
if (TLS_RELOC_P (r_type))
{
struct mips_got_entry *p;
return TRUE;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
g = htab->got_info;
if (g == NULL)
return TRUE;
/* If H is a symbol that needs a global GOT entry, but has a dynamic
symbol table index lower than any we've seen to date, record it for
- posterity. */
+ posterity. FOR_CALL is true if the caller is only interested in
+ using the GOT entry for calls. */
static bfd_boolean
mips_elf_record_global_got_symbol (struct elf_link_hash_entry *h,
bfd *abfd, struct bfd_link_info *info,
+ bfd_boolean for_call,
unsigned char tls_flag)
{
struct mips_elf_link_hash_table *htab;
struct mips_got_info *g;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
hmips = (struct mips_elf_link_hash_entry *) h;
+ if (!for_call)
+ hmips->got_only_for_calls = FALSE;
/* A global symbol in the GOT must also be in the dynamic symbol
table. */
struct mips_got_entry entry, **loc;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
g = htab->got_info;
BFD_ASSERT (g != NULL);
void **loc;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
g = htab->got_info;
BFD_ASSERT (g != NULL);
struct mips_elf_link_hash_table *htab;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
s = mips_elf_rel_dyn_section (info, FALSE);
BFD_ASSERT (s != NULL);
}
/* A mips_elf_link_hash_traverse callback for which DATA points
- to a mips_got_info. Count the number of type (3) entries. */
+ to the link_info structure. Count the number of type (3) entries
+ in the master GOT. */
static int
mips_elf_count_got_symbols (struct mips_elf_link_hash_entry *h, void *data)
{
+ struct bfd_link_info *info;
+ struct mips_elf_link_hash_table *htab;
struct mips_got_info *g;
- g = (struct mips_got_info *) data;
+ info = (struct bfd_link_info *) data;
+ htab = mips_elf_hash_table (info);
+ g = htab->got_info;
if (h->global_got_area != GGA_NONE)
{
- if (h->root.forced_local || h->root.dynindx == -1)
- {
- /* 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. */
+ /* 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)))
+ {
+ /* 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. */
if (h->global_got_area != GGA_RELOC_ONLY)
g->local_gotno++;
h->global_got_area = GGA_NONE;
}
+ else if (htab->is_vxworks
+ && h->got_only_for_calls
+ && h->root.plt.offset != MINUS_ONE)
+ /* On VxWorks, calls can refer directly to the .got.plt entry;
+ they don't need entries in the regular GOT. .got.plt entries
+ will be allocated by _bfd_mips_elf_adjust_dynamic_symbol. */
+ h->global_got_area = GGA_NONE;
else
{
g->global_gotno++;
if (entry->tls_type & GOT_TLS_IE)
g->tls_gotno += 1;
}
- else if (entry->symndx >= 0 || entry->d.h->root.forced_local)
+ else if (entry->symndx >= 0 || entry->d.h->global_got_area == GGA_NONE)
++g->local_gotno;
else
++g->global_gotno;
entry = (struct mips_got_entry *) *entryp;
info = (struct bfd_link_info *) data;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
if (entry->abfd != NULL
&& entry->symndx == -1
&& entry->d.h->needs_lazy_stub)
dynobj = elf_hash_table (info)->dynobj;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
g = htab->got_info;
g->bfd2got = htab_try_create (1, mips_elf_bfd2got_entry_hash,
mips_elf_bfd2got_entry_eq, NULL);
return NULL;
}
-/* Return whether a relocation is against a local symbol. */
+/* Return whether an input relocation is against a local symbol. */
static bfd_boolean
mips_elf_local_relocation_p (bfd *input_bfd,
const Elf_Internal_Rela *relocation,
- asection **local_sections,
- bfd_boolean check_forced)
+ asection **local_sections)
{
unsigned long r_symndx;
Elf_Internal_Shdr *symtab_hdr;
- struct mips_elf_link_hash_entry *h;
size_t extsymoff;
r_symndx = ELF_R_SYM (input_bfd, relocation->r_info);
if (elf_bad_symtab (input_bfd) && local_sections[r_symndx] != NULL)
return TRUE;
- if (check_forced)
- {
- /* Look up the hash table to check whether the symbol
- was forced local. */
- h = (struct mips_elf_link_hash_entry *)
- elf_sym_hashes (input_bfd) [r_symndx - extsymoff];
- /* Find the real hash-table entry for this symbol. */
- 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 (h->root.forced_local)
- return TRUE;
- }
-
return FALSE;
}
\f
struct mips_elf_link_hash_table *htab;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
/* This function may be called more than once. */
if (htab->sgot)
dynobj = elf_hash_table (info)->dynobj;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
/* Parse the relocation. */
r_symndx = ELF_R_SYM (input_bfd, relocation->r_info);
used in the array of hash table entries. */
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
local_p = mips_elf_local_relocation_p (input_bfd, relocation,
- local_sections, FALSE);
+ local_sections);
was_local_p = local_p;
if (! elf_bad_symtab (input_bfd))
extsymoff = symtab_hdr->sh_info;
|| ((r_type == R_MIPS_26 || r_type == R_MIPS_JALR)
&& target_is_16_bit_code_p));
- local_p = mips_elf_local_relocation_p (input_bfd, relocation,
- local_sections, TRUE);
+ local_p = h == NULL || SYMBOL_REFERENCES_LOCAL (info, &h->root);
gp0 = _bfd_get_gp_value (input_bfd);
gp = _bfd_get_gp_value (abfd);
if (gnu_local_gp_p)
symbol = gp;
- /* If we haven't already determined the GOT offset, oand we're going
+ /* Global R_MIPS_GOT_PAGE relocations are equivalent to R_MIPS_GOT_DISP.
+ The addend is applied by the corresponding R_MIPS_GOT_OFST. */
+ if (r_type == R_MIPS_GOT_PAGE && !local_p)
+ {
+ r_type = R_MIPS_GOT_DISP;
+ addend = 0;
+ }
+
+ /* If we haven't already determined the GOT offset, and we're going
to need it, get it now. */
switch (r_type)
{
- case R_MIPS_GOT_PAGE:
- case R_MIPS_GOT_OFST:
- /* We need to decay to GOT_DISP/addend if the symbol doesn't
- bind locally. */
- local_p = local_p || _bfd_elf_symbol_refs_local_p (&h->root, info, 1);
- if (local_p || r_type == R_MIPS_GOT_OFST)
- break;
- /* Fall through. */
-
case R_MIPS16_CALL16:
case R_MIPS16_GOT16:
case R_MIPS_CALL16:
}
else
{
- /* GOT_PAGE may take a non-zero addend, that is ignored in a
- GOT_PAGE relocation that decays to GOT_DISP because the
- symbol turns out to be global. The addend is then added
- as GOT_OFST. */
- BFD_ASSERT (addend == 0 || r_type == R_MIPS_GOT_PAGE);
+ BFD_ASSERT (addend == 0);
g = mips_elf_global_got_index (dynobj, input_bfd,
&h->root, r_type, info);
if (h->tls_type == GOT_NORMAL
- && (! elf_hash_table(info)->dynamic_sections_created
- || (info->shared
- && (info->symbolic || h->root.forced_local)
- && h->root.def_regular)))
- /* This is a static link or a -Bsymbolic link. The
- symbol is defined locally, or was forced to be local.
- We must initialize this entry in the GOT. */
+ && !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);
}
}
&& h->root.def_dynamic
&& !h->root.def_regular
&& !h->has_static_relocs))
- && r_symndx != 0
+ && r_symndx != STN_UNDEF
&& (h == NULL
|| h->root.root.type != bfd_link_hash_undefweak
|| ELF_ST_VISIBILITY (h->root.other) == STV_DEFAULT)
mips_elf_perform_relocation. So, we just fall through to the
R_MIPS_26 case here. */
case R_MIPS_26:
- if (local_p)
+ if (was_local_p)
value = ((addend | ((p + 4) & 0xf0000000)) + symbol) >> 2;
else
{
R_MIPS*_GOT16; every relocation evaluates to "G". */
if (!htab->is_vxworks && local_p)
{
- bfd_boolean forced;
-
- forced = ! mips_elf_local_relocation_p (input_bfd, relocation,
- local_sections, FALSE);
value = mips_elf_got16_entry (abfd, input_bfd, info,
- symbol + addend, forced);
+ symbol + addend, !was_local_p);
if (value == MINUS_ONE)
return bfd_reloc_outofrange;
value
case R_MIPS_TLS_GOTTPREL:
case R_MIPS_TLS_LDM:
case R_MIPS_GOT_DISP:
- got_disp:
value = g;
overflowed_p = mips_elf_overflow_p (value, 16);
break;
break;
case R_MIPS_GOT_PAGE:
- /* GOT_PAGE relocations that reference non-local symbols decay
- to GOT_DISP. The corresponding GOT_OFST relocation decays to
- 0. */
- if (! local_p)
- goto got_disp;
value = mips_elf_got_page (abfd, input_bfd, info, symbol + addend, NULL);
if (value == MINUS_ONE)
return bfd_reloc_outofrange;
if (!ok)
{
(*_bfd_error_handler)
- (_("%B: %A+0x%lx: jump to stub routine which is not jal"),
+ (_("%B: %A+0x%lx: Direct jumps between ISA modes are not allowed; consider recompiling with interlinking enabled."),
input_bfd,
input_section,
(unsigned long) relocation->r_offset);
struct mips_elf_link_hash_table *htab;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
r_type = ELF_R_TYPE (output_bfd, rel->r_info);
dynobj = elf_hash_table (info)->dynobj;
sreloc = mips_elf_rel_dyn_section (info, FALSE);
/* We must now calculate the dynamic symbol table index to use
in the relocation. */
- if (h != NULL
- && (!h->root.def_regular
- || (info->shared && !info->symbolic && !h->root.forced_local)))
+ if (h != NULL && ! SYMBOL_REFERENCES_LOCAL (info, &h->root))
{
+ BFD_ASSERT (htab->is_vxworks || h->global_got_area != GGA_NONE);
indx = h->root.dynindx;
if (SGI_COMPAT (output_bfd))
defined_p = h->root.def_regular;
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_OCTEON:
return bfd_mach_mips_octeon;
struct mips_elf_link_hash_table *htab;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
| SEC_LINKER_CREATED | SEC_READONLY);
Elf_Internal_Shdr *rel_hdr;
const struct elf_backend_data *bed;
- /* To determine which flavor or relocation this is, we depend on the
- fact that the INPUT_SECTION's REL_HDR is read before its REL_HDR2. */
- rel_hdr = &elf_section_data (sec)->rel_hdr;
+ /* To determine which flavor of relocation this is, we depend on the
+ fact that the INPUT_SECTION's REL_HDR is read before RELA_HDR. */
+ rel_hdr = elf_section_data (sec)->rel.hdr;
+ if (rel_hdr == NULL)
+ return FALSE;
bed = get_elf_backend_data (abfd);
- if ((size_t) (rel - relocs)
- >= (NUM_SHDR_ENTRIES (rel_hdr) * bed->s->int_rels_per_ext_rel))
- rel_hdr = elf_section_data (sec)->rel_hdr2;
- return rel_hdr->sh_entsize == MIPS_ELF_REL_SIZE (abfd);
+ return ((size_t) (rel - relocs)
+ < NUM_SHDR_ENTRIES (rel_hdr) * bed->s->int_rels_per_ext_rel);
}
/* Read the addend for REL relocation REL, which belongs to bfd ABFD.
return TRUE;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
dynobj = elf_hash_table (info)->dynobj;
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
sym_hashes = elf_sym_hashes (abfd);
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:
case R_MIPS_CALL_LO16:
if (h != NULL)
{
- /* VxWorks call relocations point at 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 || h->forced_local)
- && !mips_elf_record_global_got_symbol (h, abfd, info, 0))
+ /* Make sure there is room in the regular GOT to hold the
+ function's address. We may eliminate it in favour of
+ a .got.plt entry later; see mips_elf_count_got_symbols. */
+ if (!mips_elf_record_global_got_symbol (h, abfd, info, TRUE, 0))
return FALSE;
/* We need a stub, not a plt entry for the undefined
howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, r_type, FALSE);
addend = mips_elf_read_rel_addend (abfd, rel,
howto, contents);
- if (r_type == R_MIPS_GOT16)
+ if (got16_reloc_p (r_type))
mips_elf_add_lo16_rel_addend (abfd, rel, rel_end,
contents, &addend);
else
/* Fall through. */
case R_MIPS_GOT_DISP:
- if (h && !mips_elf_record_global_got_symbol (h, abfd, info, 0))
+ if (h && !mips_elf_record_global_got_symbol (h, abfd, info,
+ FALSE, 0))
return FALSE;
break;
case R_MIPS_TLS_LDM:
if (r_type == R_MIPS_TLS_LDM)
{
- r_symndx = 0;
+ r_symndx = STN_UNDEF;
h = NULL;
}
/* Fall through */
(struct mips_elf_link_hash_entry *) h;
hmips->tls_type |= flag;
- if (h && !mips_elf_record_global_got_symbol (h, abfd,
- info, flag))
+ if (h && !mips_elf_record_global_got_symbol (h, abfd, info,
+ FALSE, flag))
return FALSE;
}
else
{
- BFD_ASSERT (flag == GOT_TLS_LDM || r_symndx != 0);
+ BFD_ASSERT (flag == GOT_TLS_LDM || r_symndx != STN_UNDEF);
if (!mips_elf_record_local_got_symbol (abfd, r_symndx,
rel->r_addend,
case R_MIPS_HIGHEST:
/* Don't refuse a high part relocation if it's against
no symbol (e.g. part of a compound relocation). */
- if (r_symndx == 0)
+ if (r_symndx == STN_UNDEF)
break;
/* R_MIPS_HI16 against _gp_disp is used for $gp setup,
&& strcmp (h->root.root.string, "_gp_disp") == 0)
break;
+ /* Likewise __GOTT_BASE__ and __GOTT_INDEX__ on VxWorks. */
+ if (is_gott_symbol (info, h))
+ break;
+
/* FALLTHROUGH */
case R_MIPS16_26:
struct mips_elf_link_hash_table *htab;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
dynobj = elf_hash_table (info)->dynobj;
hmips = (struct mips_elf_link_hash_entry *) h;
if (do_copy)
{
/* Even though we don't directly need a GOT entry for this symbol,
- a symbol must have a dynamic symbol table index greater that
- DT_MIPS_GOTSYM if there are dynamic relocations against it. */
- if (hmips->global_got_area > GGA_RELOC_ONLY)
- hmips->global_got_area = GGA_RELOC_ONLY;
+ the SVR4 psABI requires it to have a dynamic symbol table
+ index greater that DT_MIPS_GOTSYM if there are dynamic
+ relocations against it.
+
+ VxWorks does not enforce the same mapping between the GOT
+ and the symbol table, so the same requirement does not
+ apply there. */
+ if (!htab->is_vxworks)
+ {
+ if (hmips->global_got_area > GGA_RELOC_ONLY)
+ hmips->global_got_area = GGA_RELOC_ONLY;
+ hmips->got_only_for_calls = FALSE;
+ }
mips_elf_allocate_dynamic_relocations
(dynobj, info, hmips->possibly_dynamic_relocs);
struct mips_elf_link_hash_table *htab;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
dynobj = elf_hash_table (info)->dynobj;
hmips = (struct mips_elf_link_hash_entry *) h;
struct mips_htab_traverse_info hti;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
/* The .reginfo section has a fixed size. */
ri = bfd_get_section_by_name (output_bfd, ".reginfo");
struct mips_elf_link_hash_table *htab;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
s = htab->sgot;
if (s == NULL)
return TRUE;
return FALSE;
/* Count the number of GOT symbols. */
- mips_elf_link_hash_traverse (htab, mips_elf_count_got_symbols, g);
+ mips_elf_link_hash_traverse (htab, mips_elf_count_got_symbols, info);
/* Calculate the total loadable size of the output. That
will give us the maximum number of GOT_PAGE entries
bfd_size_type dynsymcount;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
if (htab->lazy_stub_count == 0)
return;
struct mips_elf_link_hash_table *htab;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
if (htab->lazy_stub_count == 0)
return;
htab->sstubs->size = 0;
- mips_elf_link_hash_traverse (mips_elf_hash_table (info),
- mips_elf_allocate_lazy_stub, htab);
+ mips_elf_link_hash_traverse (htab, mips_elf_allocate_lazy_stub, htab);
htab->sstubs->size += htab->function_stub_size;
BFD_ASSERT (htab->sstubs->size
== htab->lazy_stub_count * htab->function_stub_size);
struct mips_elf_link_hash_table *htab;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
dynobj = elf_hash_table (info)->dynobj;
BFD_ASSERT (dynobj != NULL);
Elf_Internal_Sym *sym;
asection *sec;
- if (mips_elf_local_relocation_p (input_bfd, rel, local_sections, FALSE))
+ if (mips_elf_local_relocation_p (input_bfd, rel, local_sections))
{
r_type = ELF_R_TYPE (output_bfd, rel->r_info);
if (r_type == R_MIPS16_GPREL
asection *sec;
Elf_Internal_Shdr *symtab_hdr;
struct elf_link_hash_entry *h;
+ bfd_boolean rel_reloc;
+ rel_reloc = (NEWABI_P (input_bfd)
+ && mips_elf_rel_relocation_p (input_bfd, input_section,
+ relocs, rel));
/* Find the relocation howto for this relocation. */
- howto = MIPS_ELF_RTYPE_TO_HOWTO (input_bfd, r_type,
- NEWABI_P (input_bfd)
- && (MIPS_RELOC_RELA_P
- (input_bfd, input_section,
- rel - relocs)));
+ howto = MIPS_ELF_RTYPE_TO_HOWTO (input_bfd, r_type, !rel_reloc);
r_symndx = ELF_R_SYM (input_bfd, rel->r_info);
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
- if (mips_elf_local_relocation_p (input_bfd, rel, local_sections, FALSE))
+ if (mips_elf_local_relocation_p (input_bfd, rel, local_sections))
{
sec = local_sections[r_symndx];
h = NULL;
}
if (sec != NULL && elf_discarded_section (sec))
- {
- /* For relocs against symbols from removed linkonce sections,
- or sections discarded by a linker script, we just want the
- section contents zeroed. Avoid any special processing. */
- _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
- rel->r_info = 0;
- rel->r_addend = 0;
- continue;
- }
+ RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
+ rel, relend, howto, contents);
if (r_type == R_MIPS_64 && ! NEWABI_P (input_bfd))
{
if (hi16_reloc_p (r_type)
|| (got16_reloc_p (r_type)
&& mips_elf_local_relocation_p (input_bfd, rel,
- local_sections, FALSE)))
+ local_sections)))
{
if (!mips_elf_add_lo16_rel_addend (input_bfd, rel, relend,
contents, &addend))
struct mips_elf_link_hash_table *htab;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
BFD_ASSERT (name != NULL);
if (!htab->small_data_overflow_reported
- && (howto->type == R_MIPS_GPREL16
+ && (gprel16_reloc_p (howto->type)
|| howto->type == R_MIPS_LITERAL))
{
msg = _("small-data section exceeds 64KB;"
stub = (struct mips_elf_la25_stub *) *slot;
hti = (struct mips_htab_traverse_info *) data;
htab = mips_elf_hash_table (hti->info);
+ BFD_ASSERT (htab != NULL);
/* Create the section contents, if we haven't already. */
s = stub->stub_section;
struct mips_elf_link_hash_entry *hmips;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
dynobj = elf_hash_table (info)->dynobj;
hmips = (struct mips_elf_link_hash_entry *) h;
/* Run through the global symbol table, creating GOT entries for all
the symbols that need them. */
- if (g->global_gotsym != NULL
- && h->dynindx >= g->global_gotsym->dynindx)
+ if (hmips->global_got_area != GGA_NONE)
{
bfd_vma offset;
bfd_vma value;
MIPS_ELF_PUT_WORD (output_bfd, value, sgot->contents + offset);
}
- if (g->next && h->dynindx != -1 && h->type != STT_TLS)
+ if (hmips->global_got_area != GGA_NONE && g->next && h->type != STT_TLS)
{
struct mips_got_entry e, *p;
bfd_vma entry;
asection *sgot;
struct mips_got_info *g;
struct mips_elf_link_hash_table *htab;
+ struct mips_elf_link_hash_entry *hmips;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
dynobj = elf_hash_table (info)->dynobj;
+ hmips = (struct mips_elf_link_hash_entry *) h;
if (h->plt.offset != (bfd_vma) -1)
{
BFD_ASSERT (g != NULL);
/* See if this symbol has an entry in the GOT. */
- if (g->global_gotsym != NULL
- && h->dynindx >= g->global_gotsym->dynindx)
+ if (hmips->global_got_area != GGA_NONE)
{
bfd_vma offset;
Elf_Internal_Rela outrel;
struct mips_elf_link_hash_table *htab;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
if (ABI_64_P (output_bfd))
plt_entry = mips_n64_exec_plt0_entry;
else if (ABI_N32_P (output_bfd))
struct mips_elf_link_hash_table *htab;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
plt_entry = mips_vxworks_exec_plt0_entry;
/* Calculate the value of _GLOBAL_OFFSET_TABLE_. */
struct mips_elf_link_hash_table *htab;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
/* We just need to copy the entry byte-by-byte. */
for (i = 0; i < ARRAY_SIZE (mips_vxworks_shared_plt0_entry); i++)
struct mips_elf_link_hash_table *htab;
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
dynobj = elf_hash_table (info)->dynobj;
sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
val = E_MIPS_ARCH_64 | E_MIPS_MACH_SB1;
break;
+ case bfd_mach_mips_loongson_3a:
+ val = E_MIPS_ARCH_64 | E_MIPS_MACH_LS3A;
+ break;
+
case bfd_mach_mips_octeon:
val = E_MIPS_ARCH_64R2 | E_MIPS_MACH_OCTEON;
break;
return NULL;
}
\f
-/* Allocate ABFD's target-dependent data. */
-
-bfd_boolean
-_bfd_mips_elf_mkobject (bfd *abfd)
-{
- return bfd_elf_allocate_object (abfd, sizeof (struct elf_obj_tdata),
- MIPS_ELF_TDATA);
-}
-
/* Create a MIPS ELF linker hash table. */
struct bfd_link_hash_table *
if (!_bfd_elf_link_hash_table_init (&ret->root, abfd,
mips_elf_link_hash_newfunc,
- sizeof (struct mips_elf_link_hash_entry)))
+ sizeof (struct mips_elf_link_hash_entry),
+ MIPS_ELF_DATA))
{
free (ret);
return NULL;
/* Sort the dynamic symbols so that those with GOT entries come after
those without. */
htab = mips_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
+
if (!mips_elf_sort_hash_table (abfd, info))
return FALSE;
{ bfd_mach_mipsisa64r2, bfd_mach_mipsisa64 },
{ bfd_mach_mips_sb1, bfd_mach_mipsisa64 },
{ bfd_mach_mips_xlr, bfd_mach_mipsisa64 },
+ { bfd_mach_mips_loongson_3a, bfd_mach_mipsisa64 },
/* MIPS V extensions. */
{ bfd_mach_mipsisa64, bfd_mach_mips5 },
for (sec = ibfd->sections; sec != NULL; sec = sec->next)
{
/* Ignore synthetic sections and empty .text, .data and .bss sections
- which are automatically generated by gas. */
- if (strcmp (sec->name, ".reginfo")
+ which are automatically generated by gas. Also ignore fake
+ (s)common sections, since merely defining a common symbol does
+ not affect compatibility. */
+ if ((sec->flags & SEC_IS_COMMON) == 0
+ && strcmp (sec->name, ".reginfo")
&& strcmp (sec->name, ".mdebug")
&& (sec->size != 0
|| (strcmp (sec->name, ".text")
if (link_info)
{
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;
}