static void remember_hi16s_reloc
PARAMS ((bfd *, bfd_vma, bfd_byte *));
static bfd_byte * find_remembered_hi16s_reloc
- PARAMS ((bfd_vma addend));
+ PARAMS ((bfd_vma, boolean *));
static bfd_reloc_status_type v850_elf_final_link_relocate
PARAMS ((reloc_howto_type *, bfd *, bfd *, asection *, bfd_byte *, bfd_vma,
bfd_vma, bfd_vma, struct bfd_link_info *, asection *, int));
0xfff, /* dst_mask */
false), /* pcrel_offset */
-/* start-sanitize-v850e */
-
/* 5 bit offset from the tiny data area pointer. */
HOWTO (R_V850_TDA_4_5_OFFSET, /* type */
1, /* rightshift */
0xffff, /* dst_mask */
false), /* pcrel_offset */
-/* end-sanitize-v850e */
/* GNU extension to record C++ vtable hierarchy */
HOWTO (R_V850_GNU_VTINHERIT, /* type */
0, /* rightshift */
struct v850_elf_reloc_map
{
- unsigned char bfd_reloc_val;
+ /* BFD_RELOC_V850_CALLT_16_16_OFFSET is 258, which will not fix in an
+ unsigned char. */
+ bfd_reloc_code_real_type bfd_reloc_val;
unsigned char elf_reloc_val;
};
{ BFD_RELOC_V850_TDA_7_8_OFFSET, R_V850_TDA_7_8_OFFSET },
{ BFD_RELOC_V850_TDA_7_7_OFFSET, R_V850_TDA_7_7_OFFSET },
{ BFD_RELOC_V850_TDA_16_16_OFFSET, R_V850_TDA_16_16_OFFSET },
-/* start-sanitize-v850e */
{ BFD_RELOC_V850_TDA_4_5_OFFSET, R_V850_TDA_4_5_OFFSET },
{ BFD_RELOC_V850_TDA_4_4_OFFSET, R_V850_TDA_4_4_OFFSET },
{ BFD_RELOC_V850_SDA_16_16_SPLIT_OFFSET, R_V850_SDA_16_16_SPLIT_OFFSET },
{ BFD_RELOC_V850_ZDA_16_16_SPLIT_OFFSET, R_V850_ZDA_16_16_SPLIT_OFFSET },
{ BFD_RELOC_V850_CALLT_6_7_OFFSET, R_V850_CALLT_6_7_OFFSET },
{ BFD_RELOC_V850_CALLT_16_16_OFFSET, R_V850_CALLT_16_16_OFFSET },
-/* end-sanitize-v850e */
{ BFD_RELOC_VTABLE_INHERIT, R_V850_GNU_VTINHERIT },
{ BFD_RELOC_VTABLE_ENTRY, R_V850_GNU_VTENTRY },
case R_V850_32:
case R_V850_16:
case R_V850_8:
-/* start-sanitize-v850e */
case R_V850_CALLT_6_7_OFFSET:
case R_V850_CALLT_16_16_OFFSET:
-/* end-sanitize-v850e */
break;
/* This relocation describes the C++ object vtable hierarchy.
return false;
break;
-/* start-sanitize-v850e */
case R_V850_SDA_16_16_SPLIT_OFFSET:
-/* end-sanitize-v850e */
case R_V850_SDA_16_16_OFFSET:
case R_V850_SDA_15_16_OFFSET:
other = V850_OTHER_SDA;
common = ".scommon";
goto small_data_common;
-/* start-sanitize-v850e */
case R_V850_ZDA_16_16_SPLIT_OFFSET:
-/* end-sanitize-v850e */
case R_V850_ZDA_16_16_OFFSET:
case R_V850_ZDA_15_16_OFFSET:
other = V850_OTHER_ZDA;
common = ".zcommon";
goto small_data_common;
-/* start-sanitize-v850e */
case R_V850_TDA_4_5_OFFSET:
case R_V850_TDA_4_4_OFFSET:
-/* end-sanitize-v850e */
case R_V850_TDA_6_8_OFFSET:
case R_V850_TDA_7_8_OFFSET:
case R_V850_TDA_7_7_OFFSET:
return ret;
}
+/*
+ * In the old version, when an entry was checked out from the table,
+ * it was deleted. This produced an error if the entry was needed
+ * more than once, as the second attempted retry failed.
+ *
+ * In the current version, the entry is not deleted, instead we set
+ * the field 'found' to true. If a second lookup matches the same
+ * entry, then we know that the hi16s reloc has already been updated
+ * and does not need to be updated a second time.
+ *
+ * TODO - TOFIX: If it is possible that we need to restore 2 different
+ * addresses from the same table entry, where the first generates an
+ * overflow, whilst the second do not, then this code will fail.
+ */
+
typedef struct hi16s_location
{
bfd_vma addend;
bfd_byte * address;
unsigned long counter;
+ boolean found;
struct hi16s_location * next;
}
hi16s_location;
if (free_hi16s == NULL)
free_hi16s = (hi16s_location *) bfd_zalloc (abfd, sizeof (* free_hi16s));
- entry = free_hi16s;
+ entry = free_hi16s;
free_hi16s = free_hi16s->next;
entry->addend = addend;
entry->address = address;
entry->counter = hi16s_counter ++;
+ entry->found = false;
entry->next = previous_hi16s;
previous_hi16s = entry;
}
static bfd_byte *
-find_remembered_hi16s_reloc (addend)
- bfd_vma addend;
+find_remembered_hi16s_reloc (addend, already_found)
+ bfd_vma addend;
+ boolean * already_found;
{
hi16s_location * match = NULL;
hi16s_location * entry;
/* Search the table. Record the most recent entry that matches. */
for (entry = previous_hi16s; entry; entry = entry->next)
{
- if (entry->addend == addend)
+ if (entry->addend == addend
+ && (match == NULL || match->counter < entry->counter))
{
- if (match == NULL || match->counter < entry->counter)
- {
- previous = prev;
- match = entry;
- }
+ previous = prev;
+ match = entry;
}
-
+
prev = entry;
}
/* Extract the address. */
addr = match->address;
-
- /* Attach the entry to the free list. */
- if (previous)
- previous->next = match->next;
- else
- previous_hi16s = match->next;
-
- match->next = free_hi16s->next;
- free_hi16s = match;
-
- match->addend = 0;
- match->address = NULL;
+
+ /* Remeber if this entry has already been used before. */
+ if (already_found)
+ * already_found = match->found;
+
+ /* Note that this entry has now been used. */
+ match->found = true;
return addr;
}
|| (OVERFLOWS (addend, insn)
&& ((! BIT15_SET (insn)) || (BIT15_SET (addend)))))
{
- bfd_byte * hi16s_address = find_remembered_hi16s_reloc (addend);
+ boolean already_updated;
+ bfd_byte * hi16s_address = find_remembered_hi16s_reloc
+ (addend, & already_updated);
/* Amend the matching HI16_S relocation. */
if (hi16s_address != NULL)
{
- insn = bfd_get_16 (abfd, hi16s_address);
- insn += 1;
- bfd_put_16 (abfd, insn, hi16s_address);
+ if (! already_updated)
+ {
+ insn = bfd_get_16 (abfd, hi16s_address);
+ insn += 1;
+ bfd_put_16 (abfd, insn, hi16s_address);
+ }
}
else
{
bfd_put_8 (abfd, addend, address);
return bfd_reloc_ok;
-/* start-sanitize-v850e */
case R_V850_CALLT_16_16_OFFSET:
addend += bfd_get_16 (abfd, address);
insn = addend;
break;
-/* end-sanitize-v850e */
case R_V850_16:
insn |= addend;
break;
-/* start-sanitize-v850e */
case R_V850_TDA_4_5_OFFSET:
insn = bfd_get_16 (abfd, address);
addend += ((insn & 0xf) << 1);
insn &= 0xff80;
insn |= (addend >> 1);
break;
-/* end-sanitize-v850e */
case R_V850_GNU_VTINHERIT:
case R_V850_GNU_VTENTRY:
case R_V850_ZDA_15_16_OFFSET:
case R_V850_ZDA_16_16_OFFSET:
-/* start-sanitize-v850e */
case R_V850_ZDA_16_16_SPLIT_OFFSET:
-/* end-sanitize-v850e */
if (sym_sec == NULL)
return bfd_reloc_undefined;
case R_V850_SDA_15_16_OFFSET:
case R_V850_SDA_16_16_OFFSET:
-/* start-sanitize-v850e */
case R_V850_SDA_16_16_SPLIT_OFFSET:
-/* end-sanitize-v850e */
{
unsigned long gp;
struct bfd_link_hash_entry * h;
}
break;
-/* start-sanitize-v850e */
case R_V850_TDA_4_4_OFFSET:
case R_V850_TDA_4_5_OFFSET:
-/* end-sanitize-v850e */
case R_V850_TDA_16_16_OFFSET:
case R_V850_TDA_7_7_OFFSET:
case R_V850_TDA_7_8_OFFSET:
}
break;
-/* start-sanitize-v850e */
case R_V850_CALLT_6_7_OFFSET:
{
unsigned long ctbp;
value -= (ctbp - sym_sec->output_section->vma);
}
break;
-/* end-sanitize-v850e */
case R_V850_NONE:
case R_V850_GNU_VTINHERIT:
symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
sym_hashes = elf_sym_hashes (input_bfd);
+ if (sym_hashes == NULL)
+ {
+ info->callbacks->warning
+ (info, "no hash table available", NULL, input_bfd, input_section, 0);
+
+ return false;
+ }
+
+ /* Reset the list of remembered HI16S relocs to empty. */
+ free_hi16s = previous_hi16s;
+ previous_hi16s = NULL;
+ hi16s_counter = 0;
+
rel = relocs;
relend = relocs + input_section->reloc_count;
for (; rel < relend; rel++)
|| r_type == R_V850_GNU_VTINHERIT)
continue;
- howto = v850_elf_howto_table + r_type;
+ howto = v850_elf_howto_table + r_type;
if (info->relocateable)
{
{
default:
case E_V850_ARCH: (void) bfd_default_set_arch_mach (abfd, bfd_arch_v850, 0); break;
-/* start-sanitize-v850e */
case E_V850E_ARCH: (void) bfd_default_set_arch_mach (abfd, bfd_arch_v850, bfd_mach_v850e); break;
case E_V850EA_ARCH: (void) bfd_default_set_arch_mach (abfd, bfd_arch_v850, bfd_mach_v850ea); break;
-/* end-sanitize-v850e */
}
return true;
}
{
default:
case 0: val = E_V850_ARCH; break;
-/* start-sanitize-v850e */
case bfd_mach_v850e: val = E_V850E_ARCH; break;
case bfd_mach_v850ea: val = E_V850EA_ARCH; break;
-/* end-sanitize-v850e */
}
elf_elfheader (abfd)->e_flags &=~ EF_V850_ARCH;
{
default:
case E_V850_ARCH: fprintf (file, _("v850 architecture")); break;
-/* start-sanitize-v850e */
case E_V850E_ARCH: fprintf (file, _("v850e architecture")); break;
case E_V850EA_ARCH: fprintf (file, _("v850ea architecture")); break;
-/* end-sanitize-v850e */
}
fputc ('\n', file);