/* FR30-specific support for 32-bit ELF.
- Copyright (C) 1998 Free Software Foundation, Inc.
+ Copyright (C) 1998, 1999 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
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 boolean fr30_elf_gc_sweep_hook
+ PARAMS ((bfd *, struct bfd_link_info *, asection *, const Elf_Internal_Rela *));
+static asection * fr30_elf_gc_mark_hook
+ PARAMS ((bfd *, struct bfd_link_info *, Elf_Internal_Rela *, struct elf_link_hash_entry *, Elf_Internal_Sym *));
static reloc_howto_type fr30_elf_howto_table [] =
{
bfd_elf_generic_reloc, /* special_function */
"R_FR30_8", /* name */
true, /* partial_inplace */
- 0x0ff0, /* src_mask */
+ 0x0000, /* src_mask */
0x0ff0, /* dst_mask */
false), /* pcrel_offset */
fr30_elf_i20_reloc, /* special_function */
"R_FR30_20", /* name */
true, /* partial_inplace */
- 0x00f0ffff, /* src_mask */
+ 0x00000000, /* src_mask */
0x00f0ffff, /* dst_mask */
false), /* pcrel_offset */
bfd_elf_generic_reloc, /* special_function */
"R_FR30_32", /* name */
true, /* partial_inplace */
- 0xffffffff, /* src_mask */
+ 0x00000000, /* src_mask */
0xffffffff, /* dst_mask */
false), /* pcrel_offset */
0, /* bitpos */
complain_overflow_bitfield, /* complain_on_overflow */
fr30_elf_i32_reloc, /* special_function */
- "R_FR30_32", /* name */
+ "R_FR30_48", /* name */
true, /* partial_inplace */
- 0xffffffff, /* src_mask */
+ 0x00000000, /* src_mask */
0xffffffff, /* dst_mask */
false), /* pcrel_offset */
bfd_elf_generic_reloc, /* special_function */
"R_FR30_6_IN_4", /* name */
true, /* partial_inplace */
- 0x00f0, /* src_mask */
+ 0x0000, /* src_mask */
0x00f0, /* dst_mask */
false), /* pcrel_offset */
bfd_elf_generic_reloc,/* special_function */
"R_FR30_8_IN_8", /* name */
true, /* partial_inplace */
- 0x0ff0, /* src_mask */
+ 0x0000, /* src_mask */
0x0ff0, /* dst_mask */
false), /* pcrel_offset */
bfd_elf_generic_reloc,/* special_function */
"R_FR30_9_IN_8", /* name */
true, /* partial_inplace */
- 0x0ff0, /* src_mask */
+ 0x0000, /* src_mask */
0x0ff0, /* dst_mask */
false), /* pcrel_offset */
bfd_elf_generic_reloc,/* special_function */
"R_FR30_10_IN_8", /* name */
true, /* partial_inplace */
- 0x0ff0, /* src_mask */
+ 0x0000, /* src_mask */
0x0ff0, /* dst_mask */
false), /* pcrel_offset */
bfd_elf_generic_reloc, /* special_function */
"R_FR30_9_PCREL", /* name */
false, /* partial_inplace */
- 0x00ff, /* src_mask */
+ 0x0000, /* src_mask */
0x00ff, /* dst_mask */
false), /* pcrel_offset */
bfd_elf_generic_reloc, /* special_function */
"R_FR30_12_PCREL", /* name */
false, /* partial_inplace */
- 0x07ff, /* src_mask */
+ 0x0000, /* src_mask */
0x07ff, /* dst_mask */
false), /* pcrel_offset */
+ /* GNU extension to record C++ vtable hierarchy */
+ HOWTO (R_FR30_GNU_VTINHERIT, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 0, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ NULL, /* special_function */
+ "R_FR30_GNU_VTINHERIT", /* name */
+ false, /* partial_inplace */
+ 0, /* src_mask */
+ 0, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* GNU extension to record C++ vtable member usage */
+ HOWTO (R_FR30_GNU_VTENTRY, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 0, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ _bfd_elf_rel_vtable_reloc_fn, /* special_function */
+ "R_FR30_GNU_VTENTRY", /* name */
+ false, /* partial_inplace */
+ 0, /* src_mask */
+ 0, /* dst_mask */
+ false), /* pcrel_offset */
+
};
\f
/* Utility to actually perform an R_FR30_20 reloc. */
}
\f
-/* Utility to actually perform a R_FR30_32 reloc. */
+/* Utility to actually perform a R_FR30_48 reloc. */
static bfd_reloc_status_type
fr30_elf_i32_reloc (abfd, reloc_entry, symbol, data,
struct fr30_reloc_map
{
- unsigned int bfd_reloc_val;
+ bfd_reloc_code_real_type bfd_reloc_val;
unsigned int fr30_reloc_val;
};
{ BFD_RELOC_FR30_10_IN_8, R_FR30_10_IN_8 },
{ BFD_RELOC_FR30_9_PCREL, R_FR30_9_PCREL },
{ BFD_RELOC_FR30_12_PCREL, R_FR30_12_PCREL },
+ { BFD_RELOC_VTABLE_INHERIT, R_FR30_GNU_VTINHERIT },
+ { BFD_RELOC_VTABLE_ENTRY, R_FR30_GNU_VTENTRY },
};
static reloc_howto_type *
{
bfd_reloc_status_type r = bfd_reloc_ok;
bfd_vma x;
+ bfd_signed_vma srel;
switch (howto->type)
{
x = bfd_get_32 (input_bfd, contents);
x = (x & 0xff0f0000) | (relocation & 0x0000ffff) | ((relocation & 0x000f0000) << 4);
- bfd_put_32 (input_bfd, relocation, contents);
+ bfd_put_32 (input_bfd, x, contents);
break;
case R_FR30_48:
case R_FR30_9_PCREL:
contents += rel->r_offset + 1;
- relocation += rel->r_addend;
- relocation -= (input_section->output_section->vma +
+ srel = (bfd_signed_vma) relocation;
+ srel += rel->r_addend;
+ srel -= rel->r_offset;
+ srel -= 2; /* Branch instructions add 2 to the PC... */
+ srel -= (input_section->output_section->vma +
input_section->output_offset);
- if (relocation & 1)
+ if (srel & 1)
return bfd_reloc_outofrange;
- if (relocation > ((1 << 8) - 1) || (relocation < - (1 << 8)))
+ if (srel > ((1 << 8) - 1) || (srel < - (1 << 8)))
return bfd_reloc_overflow;
-
- bfd_put_8 (input_bfd, relocation >> 1, contents);
+
+ bfd_put_8 (input_bfd, srel >> 1, contents);
break;
case R_FR30_12_PCREL:
contents += rel->r_offset;
- relocation += rel->r_addend;
- relocation -= (input_section->output_section->vma +
+ srel = (bfd_signed_vma) relocation;
+ srel += rel->r_addend;
+ srel -= rel->r_offset;
+ srel -= 2; /* Branch instructions add 2 to the PC... */
+ srel -= (input_section->output_section->vma +
input_section->output_offset);
- if (relocation & 1)
+ if (srel & 1)
return bfd_reloc_outofrange;
- if (relocation > ((1 << 11) - 1) || (relocation < - (1 << 11)))
- return bfd_reloc_overflow;
+ if (srel > ((1 << 11) - 1) || (srel < - (1 << 11)))
+ return bfd_reloc_overflow;
x = bfd_get_16 (input_bfd, contents);
- x = (x & 0xf800) | ((relocation >> 1) & 0x7ff);
+ x = (x & 0xf800) | ((srel >> 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);
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 ++)
{
reloc_howto_type * howto;
bfd_vma relocation;
bfd_reloc_status_type r;
const char * name = NULL;
-
+ int r_type;
+
+ r_type = ELF32_R_TYPE (rel->r_info);
+
+ if ( r_type == R_FR30_GNU_VTINHERIT
+ || r_type == R_FR30_GNU_VTENTRY)
+ continue;
+
r_symndx = ELF32_R_SYM (rel->r_info);
if (info->relocateable)
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 1
+#if 0
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 1
+#if 0
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 1
+#if 0
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 1
+#if 0
fprintf (stderr, "unknown: name: %s\n", name);
#endif
relocation = 0;
return true;
}
\f
+/* Return the section that should be marked against GC for a given
+ relocation. */
+
+static asection *
+fr30_elf_gc_mark_hook (abfd, info, rel, h, sym)
+ bfd * abfd;
+ struct bfd_link_info * info;
+ Elf_Internal_Rela * rel;
+ struct elf_link_hash_entry * h;
+ Elf_Internal_Sym * sym;
+{
+ if (h != NULL)
+ {
+ switch (ELF32_R_TYPE (rel->r_info))
+ {
+ case R_FR30_GNU_VTINHERIT:
+ case R_FR30_GNU_VTENTRY:
+ break;
+
+ default:
+ switch (h->root.type)
+ {
+ case bfd_link_hash_defined:
+ case bfd_link_hash_defweak:
+ return h->root.u.def.section;
+
+ case bfd_link_hash_common:
+ return h->root.u.c.p->section;
+
+ default:
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (!(elf_bad_symtab (abfd)
+ && ELF_ST_BIND (sym->st_info) != STB_LOCAL)
+ && ! ((sym->st_shndx <= 0 || sym->st_shndx >= SHN_LORESERVE)
+ && sym->st_shndx != SHN_COMMON))
+ {
+ return bfd_section_from_elf_index (abfd, sym->st_shndx);
+ }
+ }
+
+ return NULL;
+}
+
+/* Update the got entry reference counts for the section being removed. */
+
+static boolean
+fr30_elf_gc_sweep_hook (abfd, info, sec, relocs)
+ bfd * abfd;
+ struct bfd_link_info * info;
+ asection * sec;
+ const Elf_Internal_Rela * relocs;
+{
+ return true;
+}
+
+/* Look through the relocs for a section during the first phase.
+ Since we don't do .gots or .plts, we just need to consider the
+ virtual table relocs for gc. */
+
+static boolean
+fr30_elf_check_relocs (abfd, info, sec, relocs)
+ bfd *abfd;
+ struct bfd_link_info *info;
+ asection *sec;
+ const Elf_Internal_Rela *relocs;
+{
+ Elf_Internal_Shdr *symtab_hdr;
+ struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
+ const Elf_Internal_Rela *rel;
+ const Elf_Internal_Rela *rel_end;
+
+ if (info->relocateable)
+ return true;
+
+ symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ sym_hashes = elf_sym_hashes (abfd);
+ sym_hashes_end = sym_hashes + symtab_hdr->sh_size/sizeof(Elf32_External_Sym);
+ if (!elf_bad_symtab (abfd))
+ sym_hashes_end -= symtab_hdr->sh_info;
+
+ rel_end = relocs + sec->reloc_count;
+ for (rel = relocs; rel < rel_end; rel++)
+ {
+ struct elf_link_hash_entry *h;
+ unsigned long r_symndx;
+
+ r_symndx = ELF32_R_SYM (rel->r_info);
+ if (r_symndx < symtab_hdr->sh_info)
+ h = NULL;
+ else
+ h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+
+ switch (ELF32_R_TYPE (rel->r_info))
+ {
+ /* This relocation describes the C++ object vtable hierarchy.
+ Reconstruct it for later use during GC. */
+ case R_FR30_GNU_VTINHERIT:
+ if (!_bfd_elf32_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
+ return false;
+ break;
+
+ /* This relocation describes which C++ vtable entries are actually
+ used. Record for later use during GC. */
+ case R_FR30_GNU_VTENTRY:
+ if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_addend))
+ return false;
+ break;
+ }
+ }
+
+ return true;
+}
+\f
#define ELF_ARCH bfd_arch_fr30
#define ELF_MACHINE_CODE EM_CYGNUS_FR30
#define ELF_MAXPAGESIZE 0x1000
#define elf_info_to_howto_rel NULL
#define elf_info_to_howto fr30_info_to_howto_rela
#define elf_backend_relocate_section fr30_elf_relocate_section
+#define elf_backend_gc_mark_hook fr30_elf_gc_mark_hook
+#define elf_backend_gc_sweep_hook fr30_elf_gc_sweep_hook
+#define elf_backend_check_relocs fr30_elf_check_relocs
+
+#define elf_backend_can_gc_sections 1
#define bfd_elf32_bfd_reloc_type_lookup fr30_reloc_type_lookup
-
+
#include "elf32-target.h"