/* V850-specific support for 32-bit ELF
- Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
static void v850_elf_info_to_howto_rel
PARAMS ((bfd *, arelent *, Elf32_Internal_Rel *));
+static void v850_elf_info_to_howto_rela
+ PARAMS ((bfd *, arelent *, Elf32_Internal_Rela *));
static bfd_reloc_status_type v850_elf_reloc
PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
static boolean v850_elf_is_local_label_name PARAMS ((bfd *, const char *));
Elf_Internal_Rela *,
Elf_Internal_Sym *,
asection **));
-/* Try to minimize the amount of space occupied by relocation tables
- on the ROM (not that the ROM won't be swamped by other ELF overhead). */
-#define USE_REL
/* Note: It is REQUIRED that the 'type' value of each entry in this array
match the index of the entry in the array. */
cache_ptr->howto = &v850_elf_howto_table[r_type];
}
+/* Set the howto pointer for a V850 ELF reloc (type RELA). */
+static void
+v850_elf_info_to_howto_rela (abfd, cache_ptr, dst)
+ bfd * abfd;
+ arelent * cache_ptr;
+ Elf32_Internal_Rela *dst;
+{
+ unsigned int r_type;
+
+ r_type = ELF32_R_TYPE (dst->r_info);
+ BFD_ASSERT (r_type < (unsigned int) R_V850_max);
+ cache_ptr->howto = &v850_elf_howto_table[r_type];
+}
+
\f
/* Look through the relocs for a section during the first phase, and
allocate space in the global offset table or procedure linkage
return ret;
}
+typedef struct
+{
+ long addend;
+ bfd_byte * address;
+ unsigned long counter;
+}
+hi16s_location;
+
+static hi16s_location previous_hi16s[ 10 ]; /* XXX is this enough ? */
+static unsigned long hi16s_counter;
+
+static void
+remember_hi16s_reloc (addend, address)
+ long addend;
+ bfd_byte * address;
+{
+ hi16s_location * oldest = NULL;
+ int i;
+
+ /* Find a free slot. */
+ for (i = sizeof (previous_hi16s) / sizeof (previous_hi16s[0]); i--;)
+ {
+ hi16s_location * entry = previous_hi16s + i;
+
+ if (entry->addend == 0 && entry->address == 0)
+ {
+ /* Use this entry. */
+ oldest = entry;
+ break;
+ }
+
+ /* Remember the least recently added entry. */
+ if (oldest == NULL || oldest->counter > entry->counter)
+ oldest = entry;
+ }
+
+ oldest->addend = addend;
+ oldest->address = address;
+ oldest->counter = hi16s_counter ++;
+
+ /* Cope with wrap around of our counter. */
+ if (hi16s_counter == 0)
+ {
+ /* XXX - Assume that all counter entries differ only in their low 16 bits. */
+ for (i = sizeof (previous_hi16s) / sizeof (previous_hi16s[0]); i--;)
+ {
+ hi16s_location * entry = previous_hi16s + i;
+
+ entry->counter &= 0xffff;
+ }
+
+ hi16s_counter = 0x10000;
+ }
+
+ return;
+}
+
+static bfd_byte *
+find_remembered_hi16s_reloc (addend)
+ long addend;
+{
+ hi16s_location * match = NULL;
+ int i;
+
+ /* Search the table. Record the most recent entry that matches. */
+ for (i = sizeof (previous_hi16s) / sizeof (previous_hi16s[0]); i--;)
+ {
+ hi16s_location * entry = previous_hi16s + i;
+
+ if (entry->addend == addend)
+ {
+ if (match == NULL || match->counter < entry->counter)
+ match = entry;
+ }
+ }
+
+ if (match != NULL)
+ {
+ bfd_byte * addr;
+
+ /* Empty the table entry. */
+ match->addend = 0;
+
+ addr = match->address;
+ match->address = NULL;
+
+ return addr;
+ }
+
+ return NULL;
+}
+
static bfd_reloc_status_type
-v850_elf_store_addend_in_insn (abfd, r_type, addend, address, replace)
+v850_elf_perform_relocation (abfd, r_type, addend, address)
bfd * abfd;
int r_type;
long addend;
bfd_byte * address;
- boolean replace;
{
unsigned long insn;
return bfd_reloc_notsupported;
case R_V850_32:
- if (! replace)
- addend += bfd_get_32 (abfd, address);
-
+ addend += bfd_get_32 (abfd, address);
bfd_put_32 (abfd, addend, address);
return bfd_reloc_ok;
insn |= ((addend & 0x1f0) << 7) | ((addend & 0x0e) << 3);
break;
- case R_V850_HI16_S:
- addend += bfd_get_16 (abfd, address);
- addend = (addend >> 16) + ((addend & 0x8000) != 0);
- insn = addend;
- break;
-
case R_V850_HI16:
- addend += bfd_get_16 (abfd, address);
+ addend += (bfd_get_16 (abfd, address) << 16);
addend = (addend >> 16);
insn = addend;
break;
- case R_V850_LO16:
- addend += (short) bfd_get_16 (abfd, address);
- /* Do not complain if value has top bit set, as this has been anticipated. */
+ case R_V850_HI16_S:
+ /* Remember where this relocation took place. */
+ remember_hi16s_reloc (addend, address);
+
+ addend += (bfd_get_16 (abfd, address) << 16);
+ addend = (addend >> 16) + ((addend & 0x8000) != 0);
+
+ /* This relocation cannot overflow. */
+ if (addend > 0x7fff || addend < -0x8000)
+ addend = 0;
+
insn = addend;
break;
+
+ case R_V850_LO16:
+ /* Calculate the sum of the value stored in the instruction and the
+ addend and check for overflow from the low 16 bits into the high
+ 16 bits. The assembler has already done some of this: If the
+ value stored in the instruction has its 15th bit set, (counting
+ from zero) then the assembler will have added 1 to the value
+ stored in the associated HI16S reloc. So for example, these
+ relocations:
+
+ movhi hi( fred ), r0, r1
+ movea lo( fred ), r1, r1
+
+ will store 0 in the value fields for the MOVHI and MOVEA instructions
+ and addend will be the address of fred, but for these instructions:
+
+ movhi hi( fred + 0x123456), r0, r1
+ movea lo( fred + 0x123456), r1, r1
+
+ the value stored in the MOVHI instruction will be 0x12 and the value
+ stored in the MOVEA instruction will be 0x3456. If however the
+ instructions were:
+
+ movhi hi( fred + 0x10ffff), r0, r1
+ movea lo( fred + 0x10ffff), r1, r1
+
+ then the value stored in the MOVHI instruction would be 0x11 (not
+ 0x10) and the value stored in the MOVEA instruction would be 0xffff.
+ Thus (assuming for the moment that the addend is 0), at run time the
+ MOVHI instruction loads 0x110000 into r1, then the MOVEA instruction
+ adds 0xffffffff (sign extension!) producing 0x10ffff. Similarly if
+ the instructions were:
+
+ movhi hi( fred - 1), r0, r1
+ movea lo( fred - 1), r1, r1
+
+ then 0 is stored in the MOVHI instruction and -1 is stored in the
+ MOVEA instruction.
+
+ Overflow can occur if the addition of the value stored in the
+ instruction plus the addend sets the 15th bit when before it was clear.
+ This is because the 15th bit will be sign extended into the high part,
+ thus reducing its value by one, but since the 15th bit was originally
+ clear, the assembler will not have added 1 to the previous HI16S reloc
+ to compensate for this effect. For example:
+
+ movhi hi( fred + 0x123456), r0, r1
+ movea lo( fred + 0x123456), r1, r1
+
+ The value stored in HI16S reloc is 0x12, the value stored in the LO16
+ reloc is 0x3456. If we assume that the address of fred is 0x00007000
+ then the relocations become:
+
+ HI16S: 0x0012 + (0x00007000 >> 16) = 0x12
+ LO16: 0x3456 + (0x00007000 & 0xffff) = 0xa456
+
+ but when the instructions are executed, the MOVEA instruction's value
+ is signed extended, so the sum becomes:
+
+ 0x00120000
+ + 0xffffa456
+ ------------
+ 0x0011a456 but 'fred + 0x123456' = 0x0012a456
+
+ Note that if the 15th bit was set in the value stored in the LO16
+ reloc, then we do not have to do anything:
+
+ movhi hi( fred + 0x10ffff), r0, r1
+ movea lo( fred + 0x10ffff), r1, r1
+
+ HI16S: 0x0011 + (0x00007000 >> 16) = 0x11
+ LO16: 0xffff + (0x00007000 & 0xffff) = 0x6fff
+
+ 0x00110000
+ + 0x00006fff
+ ------------
+ 0x00116fff = fred + 0x10ffff = 0x7000 + 0x10ffff
+
+
+ Overflow can also occur if the computation carries into the 16th bit
+ and it also results in the 15th bit having the same value as the 15th
+ bit of the original value. What happens is that the HI16S reloc
+ will have already examined the 15th bit of the original value and
+ added 1 to the high part if the bit is set. This compensates for the
+ sign extension of 15th bit of the result of the computation. But now
+ there is a carry into the 16th bit, and this has not been allowed for.
+
+ So, for example if fred is at address 0xf000:
+
+ movhi hi( fred + 0xffff), r0, r1 [bit 15 of the offset is set]
+ movea lo( fred + 0xffff), r1, r1
+
+ HI16S: 0x0001 + (0x0000f000 >> 16) = 0x0001
+ LO16: 0xffff + (0x0000f000 & 0xffff) = 0xefff (carry into bit 16 is lost)
+
+ 0x00010000
+ + 0xffffefff
+ ------------
+ 0x0000efff but 'fred + 0xffff' = 0x0001efff
+
+ Similarly, if the 15th bit remains clear, but overflow occurs into
+ the 16th bit then (assuming the address of fred is 0xf000):
+
+ movhi hi( fred + 0x7000), r0, r1 [bit 15 of the offset is clear]
+ movea lo( fred + 0x7000), r1, r1
+
+ HI16S: 0x0000 + (0x0000f000 >> 16) = 0x0000
+ LO16: 0x7000 + (0x0000f000 & 0xffff) = 0x6fff (carry into bit 16 is lost)
+
+ 0x00000000
+ + 0x00006fff
+ ------------
+ 0x00006fff but 'fred + 0x7000' = 0x00016fff
+
+ Note - there is no need to change anything if a carry occurs, and the
+ 15th bit changes its value from being set to being clear, as the HI16S
+ reloc will have already added in 1 to the high part for us:
+
+ movhi hi( fred + 0xffff), r0, r1 [bit 15 of the offset is set]
+ movea lo( fred + 0xffff), r1, r1
+
+ HI16S: 0x0001 + (0x00007000 >> 16)
+ LO16: 0xffff + (0x00007000 & 0xffff) = 0x6fff (carry into bit 16 is lost)
+
+ 0x00010000
+ + 0x00006fff (bit 15 not set, so the top half is zero)
+ ------------
+ 0x00016fff which is right (assuming that fred is at 0x7000)
+
+ but if the 15th bit goes from being clear to being set, then we must
+ once again handle overflow:
+
+ movhi hi( fred + 0x7000), r0, r1 [bit 15 of the offset is clear]
+ movea lo( fred + 0x7000), r1, r1
+
+ HI16S: 0x0000 + (0x0000ffff >> 16)
+ LO16: 0x7000 + (0x0000ffff & 0xffff) = 0x6fff (carry into bit 16)
+
+ 0x00000000
+ + 0x00006fff (bit 15 not set, so the top half is zero)
+ ------------
+ 0x00006fff which is wrong (assuming that fred is at 0xffff)
+ */
+
+ {
+ long result;
+
+ insn = bfd_get_16 (abfd, address);
+ result = insn + addend;
+
+#define BIT15_SET(x) ((x) & 0x8000)
+#define OVERFLOWS(a,i) ((((a) & 0xffff) + (i)) > 0xffff)
+
+ if ((BIT15_SET (result) && ! BIT15_SET (addend))
+ || (OVERFLOWS (addend, insn)
+ && ((! BIT15_SET (insn)) || (BIT15_SET (addend)))))
+ {
+ bfd_byte * hi16s_address = find_remembered_hi16s_reloc (addend);
+
+ /* 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);
+ }
+ else
+ {
+ fprintf (stderr, "FAILED to find previous HI16 reloc\n");
+ return bfd_reloc_overflow;
+ }
+ }
+
+ /* Do not complain if value has top bit set, as this has been anticipated. */
+ insn = result & 0xffff;
+ break;
+ }
+
+ case R_V850_8:
+ addend += (char) bfd_get_8 (abfd, address);
+
+ if (addend > 0x7f || addend < -0x80)
+ return bfd_reloc_overflow;
+
+ bfd_put_8 (abfd, addend, address);
+ return bfd_reloc_ok;
- case R_V850_16:
- replace = false;
- /* drop through */
-
/* start-sanitize-v850e */
case R_V850_CALLT_16_16_OFFSET:
+ addend += bfd_get_16 (abfd, address);
+
+ if (addend > 0xffff || addend < 0)
+ return bfd_reloc_overflow;
+
+ insn = addend;
+ break;
/* end-sanitize-v850e */
+
+ case R_V850_16:
+
+ /* drop through */
case R_V850_SDA_16_16_OFFSET:
case R_V850_ZDA_16_16_OFFSET:
case R_V850_TDA_16_16_OFFSET:
- if (! replace)
- addend += bfd_get_16 (abfd, address);
+ addend += bfd_get_16 (abfd, address);
if (addend > 0x7fff || addend < -0x8000)
return bfd_reloc_overflow;
case R_V850_SDA_15_16_OFFSET:
case R_V850_ZDA_15_16_OFFSET:
insn = bfd_get_16 (abfd, address);
-
- if (! replace)
- addend += ((insn & 0xfffe) << 1);
+ addend += (insn & 0xfffe);
if (addend > 0x7ffe || addend < -0x8000)
return bfd_reloc_overflow;
if (addend & 1)
- return bfd_reloc_dangerous;
+ return bfd_reloc_dangerous;
- insn &= 1;
- insn |= (addend >> 1) & ~1;
+ insn = (addend & ~1) | (insn & 1);
break;
case R_V850_TDA_6_8_OFFSET:
insn = bfd_get_16 (abfd, address);
-
- if (! replace)
- addend += ((insn & 0x7e) << 1);
+ addend += ((insn & 0x7e) << 1);
if (addend > 0xfc || addend < 0)
return bfd_reloc_overflow;
case R_V850_TDA_7_8_OFFSET:
insn = bfd_get_16 (abfd, address);
-
- if (! replace)
- addend += ((insn & 0x7f) << 1);
+ addend += ((insn & 0x7f) << 1);
if (addend > 0xfe || addend < 0)
return bfd_reloc_overflow;
case R_V850_TDA_7_7_OFFSET:
insn = bfd_get_16 (abfd, address);
-
- if (! replace)
- addend += insn & 0x7f;
+ addend += insn & 0x7f;
if (addend > 0x7f || addend < 0)
return bfd_reloc_overflow;
/* start-sanitize-v850e */
case R_V850_TDA_4_5_OFFSET:
insn = bfd_get_16 (abfd, address);
-
- if (! replace)
- addend += ((insn & 0xf) << 1);
+ addend += ((insn & 0xf) << 1);
if (addend > 0x1e || addend < 0)
return bfd_reloc_overflow;
case R_V850_TDA_4_4_OFFSET:
insn = bfd_get_16 (abfd, address);
-
- if (! replace)
- addend += insn & 0xf;
+ addend += insn & 0xf;
if (addend > 0xf || addend < 0)
return bfd_reloc_overflow;
case R_V850_ZDA_16_16_SPLIT_OFFSET:
case R_V850_SDA_16_16_SPLIT_OFFSET:
insn = bfd_get_32 (abfd, address);
-
- if (! replace)
- addend += ((insn & 0xfffe0000) >> 16) + ((insn & 0x20) >> 5);
+ addend += ((insn & 0xfffe0000) >> 16) + ((insn & 0x20) >> 5);
- if (addend > 0xffff || addend < 0)
+ if (addend > 0x7fff || addend < -0x8000)
return bfd_reloc_overflow;
insn &= 0x0001ffdf;
case R_V850_CALLT_6_7_OFFSET:
insn = bfd_get_16 (abfd, address);
-
- if (! replace)
- addend += ((insn & 0x3f) << 1);
+ addend += ((insn & 0x3f) << 1);
if (addend > 0x7e || addend < 0)
return bfd_reloc_overflow;
char ** err;
{
long relocation;
- long insn;
-
/* If there is an output BFD,
and the symbol is not a section name (which is only defined at final link time),
relocation -= reloc->address;
}
- /* I've got no clue... */
- reloc->addend = 0;
-
- return v850_elf_store_addend_in_insn (abfd, reloc->howto->type, relocation,
- (bfd_byte *) data + reloc->address, true);
+ reloc->addend = relocation;
+ return bfd_reloc_ok;
}
\f
asection * sym_sec;
int is_local;
{
- unsigned long insn;
unsigned long r_type = howto->type;
bfd_byte * hit_data = contents + offset;
+ /* Adjust the value according to the relocation. */
switch (r_type)
{
case R_V850_9_PCREL:
value -= (input_section->output_section->vma
+ input_section->output_offset);
value -= offset;
-
- if ((long)value > 0xff || (long)value < -0x100)
- return bfd_reloc_overflow;
-
- if ((value % 2) != 0)
- return bfd_reloc_dangerous;
-
- insn = bfd_get_16 (input_bfd, hit_data);
- insn &= 0x078f;
- insn |= ((value & 0x1f0) << 7) | ((value & 0x0e) << 3);
- bfd_put_16 (input_bfd, insn, hit_data);
- return bfd_reloc_ok;
+ break;
case R_V850_22_PCREL:
value -= (input_section->output_section->vma
+ offset);
value = SEXT24 (value); /* Only the bottom 24 bits of the PC are valid */
-
- if ((long)value > 0x1fffff || (long)value < -0x200000)
- return bfd_reloc_overflow;
-
- if ((value % 2) != 0)
- return bfd_reloc_dangerous;
-
- insn = bfd_get_32 (input_bfd, hit_data);
- insn &= 0x1ffc0;
- insn |= (((value & 0xfffe) << 16) | ((value & 0x3f0000) >> 16));
- bfd_put_32 (input_bfd, insn, hit_data);
- return bfd_reloc_ok;
+ break;
case R_V850_HI16_S:
- value += (short)bfd_get_16 (input_bfd, hit_data);
- value = (value >> 16) + ((value & 0x8000) != 0);
-
- if ((long)value > 0x7fff || (long)value < -0x8000)
- {
- /* This relocation cannot overflow. */
-
- value = 0;
- }
-
- bfd_put_16 (input_bfd, value, hit_data);
- return bfd_reloc_ok;
-
case R_V850_HI16:
- value += (short)bfd_get_16 (input_bfd, hit_data);
- value >>= 16;
-
- bfd_put_16 (input_bfd, value, hit_data);
- return bfd_reloc_ok;
-
case R_V850_LO16:
- value += (short)bfd_get_16 (input_bfd, hit_data);
- value &= 0xffff;
-
- bfd_put_16 (input_bfd, value, hit_data);
- return bfd_reloc_ok;
-
case R_V850_16:
- value += (short) bfd_get_16 (input_bfd, hit_data);
-
- if ((long) value > 0x7fff || (long) value < -0x8000)
- return bfd_reloc_overflow;
-
- bfd_put_16 (input_bfd, value, hit_data);
- return bfd_reloc_ok;
-
- case R_V850_ZDA_16_16_OFFSET:
- if (sym_sec == NULL)
- return bfd_reloc_undefined;
-
- value -= sym_sec->output_section->vma;
- value += (short) bfd_get_16 (input_bfd, hit_data);
-
- if ((long) value > 0x7fff || (long) value < -0x8000)
- return bfd_reloc_overflow;
-
- bfd_put_16 (input_bfd, value, hit_data);
- return bfd_reloc_ok;
+ case R_V850_32:
+ case R_V850_8:
+ break;
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;
- insn = bfd_get_16 (input_bfd, hit_data);
-
value -= sym_sec->output_section->vma;
- value += ((insn & 0xfffe) << 1);
-
- if ((long) value > 0x7ffe || (long) value < -0x8000)
- return bfd_reloc_overflow;
-
- value &= ~1;
- value |= (insn & 1);
-
- bfd_put_16 (input_bfd, value, hit_data);
- return bfd_reloc_ok;
-
- case R_V850_32:
- value += bfd_get_32 (input_bfd, hit_data);
- bfd_put_32 (input_bfd, value, hit_data);
- return bfd_reloc_ok;
-
- case R_V850_8:
- value += (char)bfd_get_8 (input_bfd, hit_data);
-
- if ((long)value > 0x7f || (long)value < -0x80)
- return bfd_reloc_overflow;
-
- bfd_put_8 (input_bfd, value, hit_data);
- return bfd_reloc_ok;
+ break;
+ case R_V850_SDA_15_16_OFFSET:
case R_V850_SDA_16_16_OFFSET:
- if (sym_sec == NULL)
- return bfd_reloc_undefined;
-
+/* start-sanitize-v850e */
+ case R_V850_SDA_16_16_SPLIT_OFFSET:
+/* end-sanitize-v850e */
{
unsigned long gp;
struct bfd_link_hash_entry * h;
- /* Get the value of __gp. */
- h = bfd_link_hash_lookup (info->hash, "__gp", false, false, true);
- if (h == (struct bfd_link_hash_entry *) NULL
- || h->type != bfd_link_hash_defined)
- return bfd_reloc_other;
-
- gp = (h->u.def.value
- + h->u.def.section->output_section->vma
- + h->u.def.section->output_offset);
-
- value -= sym_sec->output_section->vma;
- value -= (gp - sym_sec->output_section->vma);
- value += (short) bfd_get_16 (input_bfd, hit_data);
-
- if ((long)value > 0x7fff || (long)value < -0x8000)
- return bfd_reloc_overflow;
-
- bfd_put_16 (input_bfd, value, hit_data);
- return bfd_reloc_ok;
- }
-
- case R_V850_SDA_15_16_OFFSET:
- if (sym_sec == NULL)
- return bfd_reloc_undefined;
+ if (sym_sec == NULL)
+ return bfd_reloc_undefined;
- {
- unsigned long gp;
- struct bfd_link_hash_entry * h;
-
/* Get the value of __gp. */
h = bfd_link_hash_lookup (info->hash, "__gp", false, false, true);
if (h == (struct bfd_link_hash_entry *) NULL
gp = (h->u.def.value
+ h->u.def.section->output_section->vma
+ h->u.def.section->output_offset);
-
+
value -= sym_sec->output_section->vma;
value -= (gp - sym_sec->output_section->vma);
-
- insn = bfd_get_16 (input_bfd, hit_data);
-
- value += ((insn & 0xfffe) << 1);
-
- if ((long)value > 0x7ffe || (long)value < -0x8000)
- return bfd_reloc_overflow;
-
- value &= ~1;
- value |= (insn & 1);
-
- bfd_put_16 (input_bfd, value, hit_data);
- return bfd_reloc_ok;
- }
-
- case R_V850_TDA_6_8_OFFSET:
- {
- unsigned long ep;
- struct bfd_link_hash_entry * h;
-
- insn = bfd_get_16 (input_bfd, hit_data);
-
- /* Get the value of __ep. */
- h = bfd_link_hash_lookup (info->hash, "__ep", false, false, true);
- if (h == (struct bfd_link_hash_entry *) NULL
- || h->type != bfd_link_hash_defined)
- return bfd_reloc_continue; /* Actually this indicates that __ep could not be found. */
-
- ep = (h->u.def.value
- + h->u.def.section->output_section->vma
- + h->u.def.section->output_offset);
-
- value -= ep;
- value += ((insn & 0x7e) << 1);
-
- if ((long) value > 0xfc || (long) value < 0)
- return bfd_reloc_overflow;
-
- if ((value % 2) != 0)
- return bfd_reloc_dangerous;
-
- insn &= 0xff81;
- insn |= (value >> 1);
-
- bfd_put_16 (input_bfd, insn, hit_data);
- return bfd_reloc_ok;
- }
-
- case R_V850_TDA_7_8_OFFSET:
- {
- unsigned long ep;
- struct bfd_link_hash_entry * h;
-
- insn = bfd_get_16 (input_bfd, hit_data);
-
- /* Get the value of __ep. */
- h = bfd_link_hash_lookup (info->hash, "__ep", false, false, true);
- if (h == (struct bfd_link_hash_entry *) NULL
- || h->type != bfd_link_hash_defined)
- return bfd_reloc_continue; /* Actually this indicates that __ep could not be found. */
-
- ep = (h->u.def.value
- + h->u.def.section->output_section->vma
- + h->u.def.section->output_offset);
-
- value -= ep;
- value += ((insn & 0x7f) << 1);
-
- if ((long) value > 0xfe || (long) value < 0)
- return bfd_reloc_overflow;
-
- insn &= 0xff80;
- insn |= (value >> 1);
-
- bfd_put_16 (input_bfd, insn, hit_data);
- return bfd_reloc_ok;
- }
-
- case R_V850_TDA_7_7_OFFSET:
- {
- unsigned long ep;
- struct bfd_link_hash_entry * h;
-
- insn = bfd_get_16 (input_bfd, hit_data);
-
- /* Get the value of __ep. */
- h = bfd_link_hash_lookup (info->hash, "__ep", false, false, true);
- if (h == (struct bfd_link_hash_entry *) NULL
- || h->type != bfd_link_hash_defined)
- return bfd_reloc_continue; /* Actually this indicates that __ep could not be found. */
-
- ep = (h->u.def.value
- + h->u.def.section->output_section->vma
- + h->u.def.section->output_offset);
- value -= ep;
-
- value += insn & 0x7f;
-
- if ((long) value > 0x7f || (long) value < 0)
- return bfd_reloc_overflow;
-
- insn &= 0xff80;
- insn |= value;
- bfd_put_16 (input_bfd, insn, hit_data);
- return bfd_reloc_ok;
- }
-
- case R_V850_TDA_16_16_OFFSET:
- {
- unsigned long ep;
- struct bfd_link_hash_entry * h;
-
- /* Get the value of __ep. */
- h = bfd_link_hash_lookup (info->hash, "__ep", false, false, true);
- if (h == (struct bfd_link_hash_entry *) NULL
- || h->type != bfd_link_hash_defined)
- return bfd_reloc_other;
-
- ep = (h->u.def.value
- + h->u.def.section->output_section->vma
- + h->u.def.section->output_offset);
- value -= ep;
-
- value += (short) bfd_get_16 (input_bfd, hit_data);
-
- if ((long)value > 0x7fff || (long)value < -0x8000)
- return bfd_reloc_overflow;
-
- bfd_put_16 (input_bfd, value, hit_data);
- return bfd_reloc_ok;
}
+ 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:
+ case R_V850_TDA_6_8_OFFSET:
{
unsigned long ep;
struct bfd_link_hash_entry * h;
ep = (h->u.def.value
+ h->u.def.section->output_section->vma
+ h->u.def.section->output_offset);
- value -= ep;
-
- insn = bfd_get_16 (input_bfd, hit_data);
- value += ((insn & 0xf) << 1);
-
- if ((long) value > 0x1e || (long) value < 0)
- return bfd_reloc_overflow;
-
- insn &= 0xfff0;
- insn |= (value >> 1);
- bfd_put_16 (input_bfd, insn, hit_data);
- return bfd_reloc_ok;
- }
-
- case R_V850_TDA_4_4_OFFSET:
- {
- unsigned long ep;
- struct bfd_link_hash_entry * h;
-
- /* Get the value of __ep. */
- h = bfd_link_hash_lookup (info->hash, "__ep", false, false, true);
- if (h == (struct bfd_link_hash_entry *) NULL
- || h->type != bfd_link_hash_defined)
- return bfd_reloc_continue; /* Actually this indicates that __ep could not be found. */
-
- ep = (h->u.def.value
- + h->u.def.section->output_section->vma
- + h->u.def.section->output_offset);
value -= ep;
-
- insn = bfd_get_16 (input_bfd, hit_data);
-
- value += insn & 0xf;
-
- if ((long) value > 0xf || (long) value < 0)
- return bfd_reloc_overflow;
-
- insn &= 0xfff0;
- insn |= value;
- bfd_put_16 (input_bfd, insn, hit_data);
- return bfd_reloc_ok;
}
+ break;
- case R_V850_SDA_16_16_SPLIT_OFFSET:
- if (sym_sec == NULL)
- return bfd_reloc_undefined;
-
- {
- unsigned long gp;
- struct bfd_link_hash_entry * h;
-
- /* Get the value of __gp. */
- h = bfd_link_hash_lookup (info->hash, "__gp", false, false, true);
- if (h == (struct bfd_link_hash_entry *) NULL
- || h->type != bfd_link_hash_defined)
- return bfd_reloc_other;
-
- gp = (h->u.def.value
- + h->u.def.section->output_section->vma
- + h->u.def.section->output_offset);
-
- value -= sym_sec->output_section->vma;
- value -= (gp - sym_sec->output_section->vma);
-
- insn = bfd_get_32 (input_bfd, hit_data);
-
- value += ((insn & 0xfffe0000) >> 16);
- value += ((insn & 0x20) >> 5);
-
- if ((long)value > 0x7fff || (long)value < -0x8000)
- return bfd_reloc_overflow;
-
- insn &= 0x0001ffdf;
- insn |= (value & 1) << 5;
- insn |= (value & ~1) << 16;
-
- bfd_put_32 (input_bfd, insn, hit_data);
- return bfd_reloc_ok;
- }
-
- case R_V850_ZDA_16_16_SPLIT_OFFSET:
- if (sym_sec == NULL)
- return bfd_reloc_undefined;
-
- insn = bfd_get_32 (input_bfd, hit_data);
-
- value -= sym_sec->output_section->vma;
- value += ((insn & 0xfffe0000) >> 16);
- value += ((insn & 0x20) >> 5);
-
- if ((long)value > 0x7fff || (long)value < -0x8000)
- return bfd_reloc_overflow;
-
- insn &= 0x0001ffdf;
- insn |= (value & 1) << 5;
- insn |= (value & ~1) << 16;
-
- bfd_put_32 (input_bfd, insn, hit_data);
- return bfd_reloc_ok;
-
+/* start-sanitize-v850e */
case R_V850_CALLT_6_7_OFFSET:
{
unsigned long ctbp;
+ h->u.def.section->output_section->vma
+ h->u.def.section->output_offset);
value -= ctbp;
-
- insn = bfd_get_16 (input_bfd, hit_data);
-
- value += ((insn & 0x3f) << 1);
-
- if ((long) value > 0x7e || (long) value < 0)
- return bfd_reloc_overflow;
-
- insn &= 0xff80;
- insn |= (value >> 1);
- bfd_put_16 (input_bfd, insn, hit_data);
- return bfd_reloc_ok;
}
+ break;
case R_V850_CALLT_16_16_OFFSET:
- if (sym_sec == NULL)
- return bfd_reloc_undefined;
-
{
unsigned long ctbp;
struct bfd_link_hash_entry * h;
+ if (sym_sec == NULL)
+ return bfd_reloc_undefined;
+
/* Get the value of __ctbp. */
h = bfd_link_hash_lookup (info->hash, "__ctbp", false, false, true);
if (h == (struct bfd_link_hash_entry *) NULL
value -= sym_sec->output_section->vma;
value -= (ctbp - sym_sec->output_section->vma);
- value += (short) bfd_get_16 (input_bfd, hit_data);
-
- if ((long) value > 0xffff || (long) value < 0)
- return bfd_reloc_overflow;
-
- bfd_put_16 (input_bfd, value, hit_data);
- return bfd_reloc_ok;
}
-
+ break;
/* end-sanitize-v850e */
-
+
case R_V850_NONE:
return bfd_reloc_ok;
default:
return bfd_reloc_notsupported;
}
+
+ /* Perform the relocation. */
+ return v850_elf_perform_relocation (input_bfd, r_type, value+addend, hit_data);
+
}
\f
if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
{
sec = local_sections[r_symndx];
-#ifdef USE_REL
- /* The Elf_Internal_Rel structure does not have space for the
- modified addend value, so we store it in the instruction
- instead. */
-
- if (sec->output_offset + sym->st_value != 0)
- {
- if (v850_elf_store_addend_in_insn (input_bfd, r_type,
- sec->output_offset +
- sym->st_value,
- contents + rel->r_offset,
- false)
- != bfd_reloc_ok)
- {
- info->callbacks->warning
- (info,
- "Unable to handle relocation during incremental link",
- NULL, input_bfd, input_section, rel->r_offset);
- }
- }
-#else
rel->r_addend += sec->output_offset + sym->st_value;
-#endif
}
}
char * name;
name = bfd_elf_string_from_elf_section (input_bfd, symtab_hdr->sh_link, sym->st_name);
name = (name == NULL) ? "<none>" : name;
-fprintf (stderr, "local: sec: %s, sym: %s (%d), value: %x + %x + %x addend %x rel %x\n", sec->name, name, sym->st_name,
- sec->output_section->vma, sec->output_offset, sym->st_value, rel->r_addend, rel);
+fprintf (stderr, "local: sec: %s, sym: %s (%d), value: %x + %x + %x addend %x\n",
+ sec->name, name, sym->st_name,
+ sec->output_section->vma, sec->output_offset, sym->st_value, rel->r_addend);
}
#endif
}
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_V850EQ_ARCH: (void) bfd_default_set_arch_mach (abfd, bfd_arch_v850, bfd_mach_v850eq); break;
+ case E_V850EA_ARCH: (void) bfd_default_set_arch_mach (abfd, bfd_arch_v850, bfd_mach_v850ea); break;
/* end-sanitize-v850e */
}
+ return true;
}
/* Store the machine number in the flags field. */
case 0: val = E_V850_ARCH; break;
/* start-sanitize-v850e */
case bfd_mach_v850e: val = E_V850E_ARCH; break;
- case bfd_mach_v850eq: val = E_V850EQ_ARCH; break;
+ case bfd_mach_v850ea: val = E_V850EA_ARCH; break;
/* end-sanitize-v850e */
}
bfd * ibfd;
bfd * obfd;
{
- flagword old_flags;
- flagword new_flags;
+ flagword out_flags;
+ flagword in_flags;
if ( bfd_get_flavour (ibfd) != bfd_target_elf_flavour
|| bfd_get_flavour (obfd) != bfd_target_elf_flavour)
return true;
- new_flags = elf_elfheader (ibfd)->e_flags;
- old_flags = elf_elfheader (obfd)->e_flags;
+ in_flags = elf_elfheader (ibfd)->e_flags;
+ out_flags = elf_elfheader (obfd)->e_flags;
if (! elf_flags_init (obfd))
{
+ /* If the input is the default architecture then do not
+ bother setting the flags for the output architecture,
+ instead allow future merges to do this. If no future
+ merges ever set these flags then they will retain their
+ unitialised values, which surprise surprise, correspond
+ to the default values. */
+ if (bfd_get_arch_info (ibfd)->the_default)
+ return true;
+
elf_flags_init (obfd) = true;
- elf_elfheader (obfd)->e_flags = new_flags;
+ elf_elfheader (obfd)->e_flags = in_flags;
if (bfd_get_arch (obfd) == bfd_get_arch (ibfd)
&& bfd_get_arch_info (obfd)->the_default)
}
/* Check flag compatibility. */
-
- if (new_flags == old_flags)
+ if (in_flags == out_flags)
return true;
- if ((new_flags & EF_V850_ARCH) != (old_flags & EF_V850_ARCH))
- {
- _bfd_error_handler ("%s: Architecture mismatch with previous modules",
- bfd_get_filename (ibfd));
-#if 0
- bfd_set_error (bfd_error_bad_value);
- return false;
-#else
- return true;
-#endif
- }
+ if ((in_flags & EF_V850_ARCH) != (out_flags & EF_V850_ARCH)
+ && (in_flags & EF_V850_ARCH) != E_V850_ARCH)
+ _bfd_error_handler ("%s: Architecture mismatch with previous modules",
+ bfd_get_filename (ibfd));
return true;
}
BFD_ASSERT (abfd != NULL && ptr != NULL)
- fprintf (file, "private flags = %x", elf_elfheader (abfd)->e_flags);
+ fprintf (file, "private flags = %lx", elf_elfheader (abfd)->e_flags);
switch (elf_elfheader (abfd)->e_flags & EF_V850_ARCH)
{
case E_V850_ARCH: fprintf (file, ": v850 architecture"); break;
/* start-sanitize-v850e */
case E_V850E_ARCH: fprintf (file, ": v850e architecture"); break;
- case E_V850EQ_ARCH: fprintf (file, ": v850eq architecture"); break;
+ case E_V850EA_ARCH: fprintf (file, ": v850ea architecture"); break;
/* end-sanitize-v850e */
}
#define ELF_MACHINE_CODE EM_CYGNUS_V850
#define ELF_MAXPAGESIZE 0x1000
-#define elf_info_to_howto 0
+#define elf_info_to_howto v850_elf_info_to_howto_rela
#define elf_info_to_howto_rel v850_elf_info_to_howto_rel
#define elf_backend_check_relocs v850_elf_check_relocs