PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
static long mips_elf64_get_reloc_upper_bound
PARAMS ((bfd *, asection *));
+static long mips_elf64_canonicalize_reloc
+ PARAMS ((bfd *, asection *, arelent **, asymbol **));
+static long mips_elf64_get_dynamic_reloc_upper_bound PARAMS ((bfd *));
+static long mips_elf64_canonicalize_dynamic_reloc
+ PARAMS ((bfd *, arelent **, asymbol **));
static bfd_boolean mips_elf64_slurp_one_reloc_table
- PARAMS ((bfd *, asection *, asymbol **, const Elf_Internal_Shdr *));
+ PARAMS ((bfd *, asection *, Elf_Internal_Shdr *, bfd_size_type,
+ arelent *, asymbol **, bfd_boolean));
static bfd_boolean mips_elf64_slurp_reloc_table
PARAMS ((bfd *, asection *, asymbol **, bfd_boolean));
static void mips_elf64_write_relocs
return (sec->reloc_count * 3 + 1) * sizeof (arelent *);
}
-/* Read the relocations from one reloc section. */
+static long
+mips_elf64_get_dynamic_reloc_upper_bound (abfd)
+ bfd *abfd;
+{
+ return _bfd_elf_get_dynamic_reloc_upper_bound (abfd) * 3;
+}
+
+/* We must also copy more relocations than the corresponding functions
+ in elf.c would, so the two following functions are slightly
+ modified from elf.c, that multiply the external relocation count by
+ 3 to obtain the internal relocation count. */
+
+static long
+mips_elf64_canonicalize_reloc (abfd, section, relptr, symbols)
+ bfd *abfd;
+ sec_ptr section;
+ arelent **relptr;
+ asymbol **symbols;
+{
+ arelent *tblptr;
+ unsigned int i;
+ struct elf_backend_data *bed = get_elf_backend_data (abfd);
+
+ if (! bed->s->slurp_reloc_table (abfd, section, symbols, FALSE))
+ return -1;
+
+ tblptr = section->relocation;
+ for (i = 0; i < section->reloc_count * 3; i++)
+ *relptr++ = tblptr++;
+
+ *relptr = NULL;
+
+ return section->reloc_count * 3;
+}
+
+static long
+mips_elf64_canonicalize_dynamic_reloc (abfd, storage, syms)
+ bfd *abfd;
+ arelent **storage;
+ asymbol **syms;
+{
+ bfd_boolean (*slurp_relocs)
+ PARAMS ((bfd *, asection *, asymbol **, bfd_boolean));
+ asection *s;
+ long ret;
+
+ if (elf_dynsymtab (abfd) == 0)
+ {
+ bfd_set_error (bfd_error_invalid_operation);
+ return -1;
+ }
+
+ slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
+ ret = 0;
+ for (s = abfd->sections; s != NULL; s = s->next)
+ {
+ if (elf_section_data (s)->this_hdr.sh_link == elf_dynsymtab (abfd)
+ && (elf_section_data (s)->this_hdr.sh_type == SHT_REL
+ || elf_section_data (s)->this_hdr.sh_type == SHT_RELA))
+ {
+ arelent *p;
+ long count, i;
+
+ if (! (*slurp_relocs) (abfd, s, syms, TRUE))
+ return -1;
+ count = s->_raw_size / elf_section_data (s)->this_hdr.sh_entsize * 3;
+ p = s->relocation;
+ for (i = 0; i < count; i++)
+ *storage++ = p++;
+ ret += count;
+ }
+ }
+
+ *storage = NULL;
+
+ return ret;
+}
+
+/* Read the relocations from one reloc section. This is mostly copied
+ from elfcode.h, except for the changes to expand one external
+ relocation to 3 internal ones. We must unfortunately set
+ reloc_count to the number of external relocations, because a lot of
+ generic code seems to depend on this. */
static bfd_boolean
-mips_elf64_slurp_one_reloc_table (abfd, asect, symbols, rel_hdr)
+mips_elf64_slurp_one_reloc_table (abfd, asect, rel_hdr, reloc_count,
+ relents, symbols, dynamic)
bfd *abfd;
asection *asect;
+ Elf_Internal_Shdr *rel_hdr;
+ bfd_size_type reloc_count;
+ arelent *relents;
asymbol **symbols;
- const Elf_Internal_Shdr *rel_hdr;
+ bfd_boolean dynamic;
{
PTR allocated = NULL;
bfd_byte *native_relocs;
- arelent *relents;
arelent *relent;
- bfd_vma count;
bfd_vma i;
int entsize;
reloc_howto_type *howto_table;
return FALSE;
if (bfd_seek (abfd, rel_hdr->sh_offset, SEEK_SET) != 0
- || (bfd_bread (allocated, rel_hdr->sh_size, abfd) != rel_hdr->sh_size))
+ || (bfd_bread (allocated, rel_hdr->sh_size, abfd)
+ != rel_hdr->sh_size))
goto error_return;
native_relocs = (bfd_byte *) allocated;
- relents = asect->relocation + asect->reloc_count;
-
entsize = rel_hdr->sh_entsize;
BFD_ASSERT (entsize == sizeof (Elf64_Mips_External_Rel)
|| entsize == sizeof (Elf64_Mips_External_Rela));
- count = rel_hdr->sh_size / entsize;
-
if (entsize == sizeof (Elf64_Mips_External_Rel))
howto_table = mips_elf64_howto_table_rel;
else
howto_table = mips_elf64_howto_table_rela;
- relent = relents;
- for (i = 0; i < count; i++, native_relocs += entsize)
+ for (i = 0, relent = relents;
+ i < reloc_count;
+ i++, native_relocs += entsize)
{
Elf64_Mips_Internal_Rela rela;
bfd_boolean used_sym, used_ssym;
object file, and absolute for an executable file or
shared library. The address of a BFD reloc is always
section relative. */
- if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0)
+ if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0 || dynamic)
relent->address = rela.r_offset;
else
relent->address = rela.r_offset - asect->vma;
}
/* Read the relocations. On Irix 6, there can be two reloc sections
- associated with a single data section. */
+ associated with a single data section. This is copied from
+ elfcode.h as well, with changes as small as accounting for 3
+ internal relocs per external reloc and resetting reloc_count to
+ zero before processing the relocs of a section. */
static bfd_boolean
mips_elf64_slurp_reloc_table (abfd, asect, symbols, dynamic)
asymbol **symbols;
bfd_boolean dynamic;
{
- bfd_size_type amt;
struct bfd_elf_section_data * const d = elf_section_data (asect);
+ Elf_Internal_Shdr *rel_hdr;
+ Elf_Internal_Shdr *rel_hdr2;
+ bfd_size_type reloc_count;
+ bfd_size_type reloc_count2;
+ arelent *relents;
+ bfd_size_type amt;
+
+ if (asect->relocation != NULL)
+ return TRUE;
- if (dynamic)
+ if (! dynamic)
{
- bfd_set_error (bfd_error_invalid_operation);
- return FALSE;
- }
+ if ((asect->flags & SEC_RELOC) == 0
+ || asect->reloc_count == 0)
+ return TRUE;
- if (asect->relocation != NULL
- || (asect->flags & SEC_RELOC) == 0
- || asect->reloc_count == 0)
- return TRUE;
+ rel_hdr = &d->rel_hdr;
+ reloc_count = NUM_SHDR_ENTRIES (rel_hdr);
+ rel_hdr2 = d->rel_hdr2;
+ reloc_count2 = (rel_hdr2 ? NUM_SHDR_ENTRIES (rel_hdr2) : 0);
+
+ BFD_ASSERT (asect->reloc_count == reloc_count + reloc_count2);
+ BFD_ASSERT (asect->rel_filepos == rel_hdr->sh_offset
+ || (rel_hdr2 && asect->rel_filepos == rel_hdr2->sh_offset));
+
+ }
+ else
+ {
+ /* Note that ASECT->RELOC_COUNT tends not to be accurate in this
+ case because relocations against this section may use the
+ dynamic symbol table, and in that case bfd_section_from_shdr
+ in elf.c does not update the RELOC_COUNT. */
+ if (asect->_raw_size == 0)
+ return TRUE;
+
+ rel_hdr = &d->this_hdr;
+ reloc_count = NUM_SHDR_ENTRIES (rel_hdr);
+ rel_hdr2 = NULL;
+ reloc_count2 = 0;
+ }
/* Allocate space for 3 arelent structures for each Rel structure. */
- amt = asect->reloc_count;
- amt *= 3 * sizeof (arelent);
- asect->relocation = (arelent *) bfd_alloc (abfd, amt);
- if (asect->relocation == NULL)
+ amt = (reloc_count + reloc_count2) * 3 * sizeof (arelent);
+ relents = (arelent *) bfd_alloc (abfd, amt);
+ if (relents == NULL)
return FALSE;
/* The slurp_one_reloc_table routine increments reloc_count. */
asect->reloc_count = 0;
- if (! mips_elf64_slurp_one_reloc_table (abfd, asect, symbols, &d->rel_hdr))
+ if (! mips_elf64_slurp_one_reloc_table (abfd, asect,
+ rel_hdr, reloc_count,
+ relents,
+ symbols, dynamic))
return FALSE;
if (d->rel_hdr2 != NULL)
{
- if (! mips_elf64_slurp_one_reloc_table (abfd, asect, symbols,
- d->rel_hdr2))
+ if (! mips_elf64_slurp_one_reloc_table (abfd, asect,
+ rel_hdr2, reloc_count2,
+ relents + reloc_count * 3,
+ symbols, dynamic))
return FALSE;
}
+ asect->relocation = relents;
return TRUE;
}
_bfd_mips_elf_print_private_bfd_data
#define bfd_elf64_get_reloc_upper_bound mips_elf64_get_reloc_upper_bound
+#define bfd_elf64_canonicalize_reloc mips_elf64_canonicalize_reloc
+#define bfd_elf64_get_dynamic_reloc_upper_bound mips_elf64_get_dynamic_reloc_upper_bound
+#define bfd_elf64_canonicalize_dynamic_reloc mips_elf64_canonicalize_dynamic_reloc
/* MIPS ELF64 archive functions. */
#define bfd_elf64_archive_functions