/* Forward declarations. */
static bfd_reloc_status_type fr30_elf_i20_reloc
PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+static bfd_reloc_status_type fr30_elf_i32_reloc
+ PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
static reloc_howto_type * fr30_reloc_type_lookup
PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
static void fr30_info_to_howto_rela
PARAMS ((bfd *, arelent *, Elf32_Internal_Rela *));
static boolean fr30_elf_relocate_section
PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
+static bfd_reloc_status_type fr30_final_link_relocate
+ PARAMS ((reloc_howto_type *, bfd *, asection *, bfd_byte *, Elf_Internal_Rela *, bfd_vma));
static reloc_howto_type fr30_elf_howto_table [] =
{
0xffffffff, /* dst_mask */
false), /* pcrel_offset */
+ /* A 32 bit into 48 bits absolute relocation. */
+ HOWTO (R_FR30_48, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ fr30_elf_i32_reloc, /* special_function */
+ "R_FR30_32", /* name */
+ true, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ false), /* pcrel_offset */
+
/* A 6 bit absolute relocation. */
HOWTO (R_FR30_6_IN_4, /* type */
2, /* rightshift */
true, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ bfd_elf_generic_reloc, /* special_function */
"R_FR30_9_PCREL", /* name */
false, /* partial_inplace */
0x00ff, /* src_mask */
0x00ff, /* dst_mask */
- true), /* pcrel_offset */
+ false), /* pcrel_offset */
/* A PC relative 12 bit relocation, right shifted by 1. */
HOWTO (R_FR30_12_PCREL, /* type */
true, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ bfd_elf_generic_reloc, /* special_function */
"R_FR30_12_PCREL", /* name */
false, /* partial_inplace */
0x07ff, /* src_mask */
0x07ff, /* dst_mask */
- true), /* pcrel_offset */
+ false), /* pcrel_offset */
};
\f
/* Utility to actually perform an R_FR30_20 reloc. */
if (output_bfd != NULL)
/* FIXME: See bfd_perform_relocation. Is this right? */
- return bfd_reloc_continue;
+ return bfd_reloc_ok;
relocation =
symbol->value
return bfd_reloc_ok;
}
+\f
+/* Utility to actually perform a R_FR30_48 reloc. */
+
+static bfd_reloc_status_type
+fr30_elf_i32_reloc (abfd, reloc_entry, symbol, data,
+ input_section, output_bfd, error_message)
+ bfd * abfd;
+ arelent * reloc_entry;
+ asymbol * symbol;
+ PTR data;
+ asection * input_section;
+ bfd * output_bfd;
+ char ** error_message;
+{
+ bfd_vma relocation;
+
+ /* This part is from bfd_elf_generic_reloc. */
+ if (output_bfd != (bfd *) NULL
+ && (symbol->flags & BSF_SECTION_SYM) == 0
+ && (! reloc_entry->howto->partial_inplace
+ || reloc_entry->addend == 0))
+ {
+ reloc_entry->address += input_section->output_offset;
+ return bfd_reloc_ok;
+ }
+
+ if (output_bfd != NULL)
+ /* FIXME: See bfd_perform_relocation. Is this right? */
+ return bfd_reloc_ok;
+
+ relocation =
+ symbol->value
+ + symbol->section->output_section->vma
+ + symbol->section->output_offset
+ + reloc_entry->addend;
+
+ bfd_put_32 (abfd, relocation, data + reloc_entry->address + 2);
+
+ return bfd_reloc_ok;
+}
\f
/* Map BFD reloc types to FR30 ELF reloc types. */
{ BFD_RELOC_8, R_FR30_8 },
{ BFD_RELOC_FR30_20, R_FR30_20 },
{ BFD_RELOC_32, R_FR30_32 },
+ { BFD_RELOC_FR30_48, R_FR30_48 },
{ BFD_RELOC_FR30_6_IN_4, R_FR30_6_IN_4 },
{ BFD_RELOC_FR30_8_IN_8, R_FR30_8_IN_8 },
{ BFD_RELOC_FR30_9_IN_8, R_FR30_9_IN_8 },
BFD_ASSERT (r_type < (unsigned int) R_FR30_max);
cache_ptr->howto = & fr30_elf_howto_table [r_type];
}
+\f
+/* Perform a single relocation. By default we use the standard BFD
+ routines, but a few relocs, we have to do them ourselves. */
+
+static bfd_reloc_status_type
+fr30_final_link_relocate (howto, input_bfd, input_section, contents, rel, relocation)
+ reloc_howto_type * howto;
+ bfd * input_bfd;
+ asection * input_section;
+ bfd_byte * contents;
+ Elf_Internal_Rela * rel;
+ bfd_vma relocation;
+{
+ bfd_reloc_status_type r = bfd_reloc_ok;
+ bfd_vma x;
+
+ switch (howto->type)
+ {
+ case R_FR30_20:
+ contents += rel->r_offset;
+ relocation += rel->r_addend;
+
+ if (relocation > ((1 << 20) - 1))
+ return bfd_reloc_overflow;
+
+ x = bfd_get_32 (input_bfd, contents);
+ x = (x & 0xff0f0000) | (relocation & 0x0000ffff) | ((relocation & 0x000f0000) << 4);
+ bfd_put_32 (input_bfd, relocation, contents);
+ break;
+
+ case R_FR30_48:
+ contents += rel->r_offset + 2;
+ relocation += rel->r_addend;
+ bfd_put_32 (input_bfd, relocation, contents);
+ break;
+
+ case R_FR30_9_PCREL:
+ contents += rel->r_offset + 1;
+ relocation += rel->r_addend;
+ relocation -= (input_section->output_section->vma +
+ input_section->output_offset);
+
+ if (relocation & 1)
+ return bfd_reloc_outofrange;
+ if (relocation > ((1 << 8) - 1) || (relocation < - (1 << 8)))
+ return bfd_reloc_overflow;
+
+ bfd_put_8 (input_bfd, relocation >> 1, contents);
+ break;
+
+ case R_FR30_12_PCREL:
+ contents += rel->r_offset;
+ relocation += rel->r_addend;
+ relocation -= (input_section->output_section->vma +
+ input_section->output_offset);
+
+ if (relocation & 1)
+ return bfd_reloc_outofrange;
+ if (relocation > ((1 << 11) - 1) || (relocation < - (1 << 11)))
+ return bfd_reloc_overflow;
+
+ x = bfd_get_16 (input_bfd, contents);
+ x = (x & 0xf800) | ((relocation >> 1) & 0x7ff);
+ bfd_put_16 (input_bfd, x, contents);
+ break;
+
+ default:
+fprintf (stderr, " type: %d offset: %x, before: %x\n",
+ howto->type, rel->r_offset, bfd_get_32 (input_bfd, contents + rel->r_offset));
+
+ r = _bfd_final_link_relocate (howto, input_bfd, input_section,
+ contents, rel->r_offset,
+ relocation, rel->r_addend);
+ }
+
+ return r;
+}
+
\f
/* Relocate an FR30 ELF section.
There is some attempt to make this function usable for many architectures,
symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
sym_hashes = elf_sym_hashes (input_bfd);
relend = relocs + input_section->reloc_count;
+
+fprintf (stderr, "Relocate section: %s\n", bfd_section_name (input_bfd, input_section));
for (rel = relocs; rel < relend; rel ++)
{
struct elf_link_hash_entry * h;
bfd_vma relocation;
bfd_reloc_status_type r;
- const char * name;
+ const char * name = NULL;
r_symndx = ELF32_R_SYM (rel->r_info);
name = bfd_elf_string_from_elf_section
(input_bfd, symtab_hdr->sh_link, sym->st_name);
name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
-#if 0
+#if 1
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,
relocation = (h->root.u.def.value
+ sec->output_section->vma
+ sec->output_offset);
-#if 0
+#if 1
fprintf (stderr,
"defined: sec: %s, name: %s, value: %x + %x + %x gives: %x\n",
sec->name, name, h->root.u.def.value,
}
else if (h->root.type == bfd_link_hash_undefweak)
{
-#if 0
+#if 1
fprintf (stderr, "undefined: sec: %s, name: %s\n",
sec->name, name);
#endif
(info, h->root.root.string, input_bfd,
input_section, rel->r_offset)))
return false;
-#if 0
+#if 1
fprintf (stderr, "unknown: name: %s\n", name);
#endif
relocation = 0;
}
}
-
- r = _bfd_final_link_relocate (howto, input_bfd, input_section,
- contents, rel->r_offset,
- relocation, rel->r_addend);
+
+ r = fr30_final_link_relocate (howto, input_bfd, input_section,
+ contents, rel, relocation);
if (r != bfd_reloc_ok)
{
- const char * msg = (const char *)0;
+ const char * msg = (const char *) NULL;
switch (r)
{
case bfd_reloc_overflow:
- if (! ((*info->callbacks->reloc_overflow)
- (info, name, howto->name, (bfd_vma) 0,
- input_bfd, input_section, rel->r_offset)))
- return false;
+ r = info->callbacks->reloc_overflow
+ (info, name, howto->name, (bfd_vma) 0,
+ input_bfd, input_section, rel->r_offset);
break;
-
+
case bfd_reloc_undefined:
- if (! ((*info->callbacks->undefined_symbol)
- (info, name, input_bfd, input_section,
- rel->r_offset)))
- return false;
+ r = info->callbacks->undefined_symbol
+ (info, name, input_bfd, input_section, rel->r_offset);
break;
-
+
case bfd_reloc_outofrange:
msg = _("internal error: out of range error");
- goto common_error;
+ break;
case bfd_reloc_notsupported:
msg = _("internal error: unsupported relocation error");
- goto common_error;
+ break;
case bfd_reloc_dangerous:
msg = _("internal error: dangerous relocation");
- goto common_error;
-
- case bfd_reloc_other:
- msg = _("could not locate special linker symbol __gp");
- goto common_error;
-
- case bfd_reloc_continue:
- msg = _("could not locate special linker symbol __ep");
- goto common_error;
+ break;
- case (bfd_reloc_dangerous + 1):
- msg = _("could not locate special linker symbol __ctbp");
- goto common_error;
-
default:
msg = _("internal error: unknown error");
- /* fall through */
-
- common_error:
- if (!((*info->callbacks->warning)
- (info, msg, name, input_bfd, input_section,
- rel->r_offset)))
- return false;
break;
}
+
+ if (msg)
+ r = info->callbacks->warning
+ (info, msg, name, input_bfd, input_section, rel->r_offset);
+
+ if (! r)
+ return false;
}
}