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. */
-#include "bfd.h"
#include "sysdep.h"
+#include "bfd.h"
#include "libbfd.h"
#include "elf-bfd.h"
#include "opcode/ia64.h"
return lookup_howto (rtype);
}
+static reloc_howto_type *
+elfNN_ia64_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+ const char *r_name)
+{
+ unsigned int i;
+
+ for (i = 0;
+ i < sizeof (ia64_howto_table) / sizeof (ia64_howto_table[0]);
+ i++)
+ if (ia64_howto_table[i].name != NULL
+ && strcasecmp (ia64_howto_table[i].name, r_name) == 0)
+ return &ia64_howto_table[i];
+
+ return NULL;
+}
+
/* Given a ELF reloc, return the matching HOWTO structure. */
static void
sort_dyn_sym_info (struct elfNN_ia64_dyn_sym_info *info,
unsigned int count)
{
- bfd_vma curr, prev;
- unsigned int i, dup, diff, dest, src, len;
+ bfd_vma curr, prev, got_offset;
+ unsigned int i, kept, dup, diff, dest, src, len;
qsort (info, count, sizeof (*info), addend_compare);
/* Find the first duplicate. */
prev = info [0].addend;
+ got_offset = info [0].got_offset;
for (i = 1; i < count; i++)
{
curr = info [i].addend;
if (curr == prev)
- break;
+ {
+ /* For duplicates, make sure that GOT_OFFSET is valid. */
+ if (got_offset == (bfd_vma) -1)
+ got_offset = info [i].got_offset;
+ break;
+ }
+ got_offset = info [i].got_offset;
prev = curr;
}
+ /* We may move a block of elements to here. */
+ dest = i++;
+
/* Remove duplicates. */
if (i < count)
{
- /* We need to move a block of elements to here. */
- dest = i++;
while (i < count)
{
+ /* For duplicates, make sure that the kept one has a valid
+ got_offset. */
+ kept = dest - 1;
+ if (got_offset != (bfd_vma) -1)
+ info [kept].got_offset = got_offset;
+
curr = info [i].addend;
+ got_offset = info [i].got_offset;
/* Move a block of elements whose first one is different from
the previous. */
if (curr == prev)
{
for (src = i + 1; src < count; src++)
- if (info [src].addend != curr)
- break;
+ {
+ if (info [src].addend != curr)
+ break;
+ /* For duplicates, make sure that GOT_OFFSET is
+ valid. */
+ if (got_offset == (bfd_vma) -1)
+ got_offset = info [src].got_offset;
+ }
+
+ /* Make sure that the kept one has a valid got_offset. */
+ if (got_offset != (bfd_vma) -1)
+ info [kept].got_offset = got_offset;
}
else
src = i;
if (src >= count)
break;
- /* Find the next duplicate. */
+ /* Find the next duplicate. SRC will be kept. */
prev = info [src].addend;
+ got_offset = info [src].got_offset;
for (dup = src + 1; dup < count; dup++)
{
curr = info [dup].addend;
if (curr == prev)
- break;
+ {
+ /* Make sure that got_offset is valid. */
+ if (got_offset == (bfd_vma) -1)
+ got_offset = info [dup].got_offset;
+
+ /* For duplicates, make sure that the kept one has
+ a valid got_offset. */
+ if (got_offset != (bfd_vma) -1)
+ info [dup - 1].got_offset = got_offset;
+ break;
+ }
+ got_offset = info [dup].got_offset;
prev = curr;
}
if (len == 1 && dup < count)
{
/* If we only move 1 element, we combine it with the next
- one. Find the next different one. */
+ one. There must be at least a duplicate. Find the
+ next different one. */
for (diff = dup + 1, src++; diff < count; diff++, src++)
- if (info [diff].addend != curr)
- break;
+ {
+ if (info [diff].addend != curr)
+ break;
+ /* Make sure that got_offset is valid. */
+ if (got_offset == (bfd_vma) -1)
+ got_offset = info [diff].got_offset;
+ }
+
+ /* Makre sure that the last duplicated one has an valid
+ offset. */
+ BFD_ASSERT (curr == prev);
+ if (got_offset != (bfd_vma) -1)
+ info [diff - 1].got_offset = got_offset;
if (diff < count)
{
- /* Find the next duplicate. */
+ /* Find the next duplicate. Track the current valid
+ offset. */
prev = info [diff].addend;
+ got_offset = info [diff].got_offset;
for (dup = diff + 1; dup < count; dup++)
{
curr = info [dup].addend;
if (curr == prev)
- break;
+ {
+ /* For duplicates, make sure that GOT_OFFSET
+ is valid. */
+ if (got_offset == (bfd_vma) -1)
+ got_offset = info [dup].got_offset;
+ break;
+ }
+ got_offset = info [dup].got_offset;
prev = curr;
diff++;
}
count = dest;
}
+ else
+ {
+ /* When we get here, either there is no duplicate at all or
+ the only duplicate is the last element. */
+ if (dest < count)
+ {
+ /* If the last element is a duplicate, make sure that the
+ kept one has a valid got_offset. We also update count. */
+ if (got_offset != (bfd_vma) -1)
+ info [dest - 1].got_offset = got_offset;
+ count = dest;
+ }
+ }
return count;
}
/* Append the new one to the array. */
dyn_i = info + count;
memset (dyn_i, 0, sizeof (*dyn_i));
+ dyn_i->got_offset = (bfd_vma) -1;
dyn_i->addend = addend;
/* We increment count only since the new ones are unsorted and
- sym_sec->output_section->vma
- sym_sec->output_offset;
}
-
- qsort (loc_h->info, loc_h->count,
- sizeof (*loc_h->info), addend_compare);
+
+ /* We may have introduced duplicated entries. We need
+ to remove them properly. */
+ count = sort_dyn_sym_info (loc_h->info, loc_h->count);
+ if (count != loc_h->count)
+ {
+ loc_h->count = count;
+ loc_h->sorted_count = count;
+ }
loc_h->sec_merge_done = 1;
}
#define bfd_elfNN_bfd_reloc_type_lookup \
elfNN_ia64_reloc_type_lookup
+#define bfd_elfNN_bfd_reloc_name_lookup \
+ elfNN_ia64_reloc_name_lookup
#define bfd_elfNN_bfd_is_local_label_name \
elfNN_ia64_is_local_label_name
#define bfd_elfNN_bfd_relax_section \
#define elf_backend_reloc_type_class elfNN_ia64_reloc_type_class
#define elf_backend_rela_normal 1
#define elf_backend_special_sections elfNN_ia64_special_sections
+#define elf_backend_default_execstack 0
/* FIXME: PR 290: The Intel C compiler generates SHT_IA_64_UNWIND with
SHF_LINK_ORDER. But it doesn't set the sh_link or sh_info fields.