This is the mail archive of the binutils@sources.redhat.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH]: Merge bfd HC11/HC12 code together and add trampoline generationsupport


Hi!

This (big) patch:

  - merges several HC11/HC12 functions from elf32-m68hc11.c and elf32-m68hc12.c
    in a new file elf32-m68hc1x.c.  These functions were identical and were duplicated.
    What remains in elf32-m68hc11.c and elf32-m68hc12.c are the specific stuff like
    reloc tables, linker relaxation, and stub generation.

  - adds support for trampoline generation following the hppa model.
    In elf32_m68hc11_size_stubs() we gather all the symbols for analysis and
    we look at each reloc for a 16-bit reloc against a symbol marked STO_M68HC12_FAR.
    Such relocs must be made against a trampoline code.  We remember the trampoline
    and its jump address to a hash table (more or less like what hppa did).

    size_stubs() is called at least twice: first to obtain the list of trampolines
    and know their size; second after linker GC and linker relaxation to obtain/update
    the address of the trampoline jump point.

    When applying relocation, we change the 16-bit relocs to a STO_M68HC12_FAR symbol
    to the trampoline entry point (instead of the function itself).  Other relocs need
    not be changed.

This patch only contains the HC11/HC12 bfd specific part.  A next patch necessary to
it updates the configure.in and Makefile.am.

I plan to commit this on Monday.

Stephane

2003-04-18 Stephane Carrez <stcarrez at nerim dot fr>

	* elf32-m68hc1x.c: New file (from elf32-m68hc11.c and elf32-m68hc12.c)
	(m68hc11_elf_hash_table_create): New function.
	(elf32_m68hc11_link_hash_table_free): New function.
	(stub_hash_newfunc): New function.
	(m68hc11_add_stub): New function.
	(elf32_m68hc11_add_symbol_hook): New function.
	(elf32_m68hc11_setup_section_lists): New function.
	(elf32_m68hc11_next_input_section): New function.
	(elf32_m68hc11_size_stubs): New function.
	(elf32_m68hc11_build_stubs): New function.
	(m68hc11_get_relocation_value): New function.
	(elf32_m68hc11_relocate_section): Call the above to redirect
	some relocations to the trampoline code.
	(m68hc11_elf_export_one_stub): New function.
	(m68hc11_elf_set_symbol): New function.
	(elf32_m68hc11_build_stubs): Call it via bfd_hash_traverse.
	(m68hc11_elf_get_bank_parameters): Get parameters only when the info
	is not yet initialized.

	* elf32-m68hc1x.h: New file (from elf32-m68hc11.c and elf32-m68hc12.c)
	(elf32_m68hc11_stub_hash_entry): New struct.
	(m68hc11_page_info): Add trampoline handler address.
	(m68hc11_elf_link_hash_table): Add stubs generation members.
	(elf32_m68hc11_add_symbol_hook): Declare.
	(elf32_m68hc11_setup_section_lists): Declare.
	(elf32_m68hc11_size_stubs): Declare.
	(elf32_m68hc11_build_stubs): Declare.
	
	* elf32-m68hc11.c (m68hc11_elf_ignore_reloc): Move to elf32-m68hc1x.c.
	(elf32_m68hc11_gc_mark_hook, elf32_m68hc11_gc_sweep_hook): Likewise.
	(elf32_m68hc11_check_relocs, elf32_m68hc11_relocate_section): Ditto.
	(_bfd_m68hc11_elf_set_private_flags): Ditto.
	(_bfd_m68hc11_elf_merge_private_bfd_data): Ditto.
	(_bfd_m68hc11_elf_print_private_bfd_data): Ditto.
	(bfd_elf32_bfd_link_hash_table_create): Define.
	(elf_backend_add_symbol_hook): Define.
	(m68hc11_elf_bfd_link_hash_table_create): New function.
	(m68hc11_elf_build_one_stub): New function.
	(m68hc11_elf_size_one_stub): New function.
	(m68hc11_elf_bfd_link_hash_table_create): Install the above.
	(bfd_elf32_bfd_link_hash_table_create): Define.

	* elf32-m68hc12.c (m68hc11_elf_ignore_reloc): Remove.
	(m68hc12_addr_is_banked): Remove, use m68hc11_addr_is_banked.
	(m68hc12_phys_addr): Ditto.
	(m68hc12_phys_page): Ditto.
	(m68hc12_elf_special_reloc): Move to elf32-m68hc1x.c.
	(elf32_m68hc11_gc_mark_hook): Likewise.
	(elf32_m68hc11_gc_sweep_hook): Likewise.
	(elf32_m68hc11_check_relocs): Likewise.
	(elf32_m68hc11_relocate_section): Likewise.
	(_bfd_m68hc12_elf_set_private_flags): Likewise.
	(_bfd_m68hc12_elf_merge_private_bfd_data): Likewise.
	(_bfd_m68hc12_elf_print_private_bfd_data): Likewise.
	(m68hc12_elf_build_one_stub): New function.
	(m68hc12_elf_size_one_stub): New function.
	(m68hc12_elf_bfd_link_hash_table_create): New function, use the above.
	(elf_backend_add_symbol_hook): Define.
	(elf_m68hc11_howto_table): Use TRUE for pcrel relocs; fix masks.
Index: elf32-m68hc11.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-m68hc11.c,v
retrieving revision 1.16
diff -u -p -r1.16 elf32-m68hc11.c
--- elf32-m68hc11.c	4 Apr 2003 21:17:06 -0000	1.16
+++ elf32-m68hc11.c	19 Apr 2003 08:54:54 -0000
@@ -24,29 +24,25 @@ Foundation, Inc., 59 Temple Place - Suit
 #include "bfdlink.h"
 #include "libbfd.h"
 #include "elf-bfd.h"
+#include "elf32-m68hc1x.h"
 #include "elf/m68hc11.h"
+#include "opcode/m68hc11.h"
 
+/* Relocation functions.  */
 static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup
   PARAMS ((bfd *, bfd_reloc_code_real_type));
 static void m68hc11_info_to_howto_rel
   PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
 
-static bfd_reloc_status_type m68hc11_elf_ignore_reloc
-  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+/* Trampoline generation.  */
+static bfd_boolean m68hc11_elf_size_one_stub
+  PARAMS((struct bfd_hash_entry *gen_entry, PTR in_arg));
+static bfd_boolean m68hc11_elf_build_one_stub
+  PARAMS((struct bfd_hash_entry *gen_entry, PTR in_arg));
+static struct bfd_link_hash_table* m68hc11_elf_bfd_link_hash_table_create
+  PARAMS ((bfd* abfd));
 
-/* GC mark and sweep.  */
-static asection *elf32_m68hc11_gc_mark_hook
-  PARAMS ((asection *, struct bfd_link_info *, Elf_Internal_Rela *,
-	   struct elf_link_hash_entry *, Elf_Internal_Sym *));
-static bfd_boolean elf32_m68hc11_gc_sweep_hook
-  PARAMS ((bfd *, struct bfd_link_info *, asection *,
-	   const Elf_Internal_Rela *));
-static bfd_boolean elf32_m68hc11_check_relocs
-  PARAMS ((bfd *, struct bfd_link_info *, asection *,
-	   const Elf_Internal_Rela *));
-static bfd_boolean elf32_m68hc11_relocate_section
-  PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
-	   Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
+/* Linker relaxation.  */
 static bfd_boolean m68hc11_elf_relax_section
   PARAMS ((bfd *, asection *, struct bfd_link_info *, bfd_boolean *));
 static void m68hc11_elf_relax_delete_bytes
@@ -56,18 +52,14 @@ static void m68hc11_relax_group
 	   unsigned long, unsigned long));
 static int compare_reloc PARAMS ((const void *, const void *));
 
-
-bfd_boolean _bfd_m68hc11_elf_merge_private_bfd_data PARAMS ((bfd *, bfd *));
-bfd_boolean _bfd_m68hc11_elf_set_private_flags PARAMS ((bfd *, flagword));
-bfd_boolean _bfd_m68hc11_elf_print_private_bfd_data PARAMS ((bfd *, PTR));
-
 /* Use REL instead of RELA to save space */
 #define USE_REL	1
 
-/* The Motorola 68HC11 microcontroler only addresses 64Kb.
+/* The Motorola 68HC11 microcontroller only addresses 64Kb but we also
+   support a memory bank switching mechanism similar to 68HC12.
    We must handle 8 and 16-bit relocations.  The 32-bit relocation
-   is defined but not used except by gas when -gstabs is used (which
-   is wrong).
+   are used for debugging sections (DWARF2) to represent a virtual
+   address.
    The 3-bit and 16-bit PC rel relocation is only used by 68HC12.  */
 static reloc_howto_type elf_m68hc11_howto_table[] = {
   /* This reloc does nothing.  */
@@ -367,25 +359,6 @@ bfd_elf32_bfd_reloc_type_lookup (abfd, c
   return NULL;
 }
 
-/* This function is used for relocs which are only used for relaxing,
-   which the linker should otherwise ignore.  */
-
-static bfd_reloc_status_type
-m68hc11_elf_ignore_reloc (abfd, reloc_entry, symbol, data, input_section,
-                          output_bfd, error_message)
-     bfd *abfd ATTRIBUTE_UNUSED;
-     arelent *reloc_entry;
-     asymbol *symbol ATTRIBUTE_UNUSED;
-     PTR data ATTRIBUTE_UNUSED;
-     asection *input_section;
-     bfd *output_bfd;
-     char **error_message ATTRIBUTE_UNUSED;
-{
-  if (output_bfd != NULL)
-    reloc_entry->address += input_section->output_offset;
-  return bfd_reloc_ok;
-}
-
 /* Set the howto pointer for an M68HC11 ELF reloc.  */
 
 static void
@@ -401,50 +374,106 @@ m68hc11_info_to_howto_rel (abfd, cache_p
   cache_ptr->howto = &elf_m68hc11_howto_table[r_type];
 }
 
-static asection *
-elf32_m68hc11_gc_mark_hook (sec, info, rel, h, sym)
-     asection *sec;
-     struct bfd_link_info *info ATTRIBUTE_UNUSED;
-     Elf_Internal_Rela *rel;
-     struct elf_link_hash_entry *h;
-     Elf_Internal_Sym *sym;
-{
-  if (h != NULL)
-    {
-      switch (ELF32_R_TYPE (rel->r_info))
-	{
-	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;
+
+/* Far trampoline generation.  */
 
-	    default:
-	      break;
-	    }
-	}
-    }
-  else
-    return bfd_section_from_elf_index (sec->owner, sym->st_shndx);
+/* Build a 68HC11 trampoline stub.  */
+static bfd_boolean
+m68hc11_elf_build_one_stub (gen_entry, in_arg)
+     struct bfd_hash_entry *gen_entry;
+     PTR in_arg;
+{
+  struct elf32_m68hc11_stub_hash_entry *stub_entry;
+  struct bfd_link_info *info;
+  struct m68hc11_elf_link_hash_table *htab;
+  asection *stub_sec;
+  bfd *stub_bfd;
+  bfd_byte *loc;
+  bfd_vma sym_value, phys_page, phys_addr;
+
+  /* Massage our args to the form they really have.  */
+  stub_entry = (struct elf32_m68hc11_stub_hash_entry *) gen_entry;
+  info = (struct bfd_link_info *) in_arg;
+
+  htab = m68hc11_elf_hash_table (info);
+
+  stub_sec = stub_entry->stub_sec;
+
+  /* Make a note of the offset within the stubs for this entry.  */
+  stub_entry->stub_offset = stub_sec->_raw_size;
+  stub_sec->_raw_size += 10;
+  loc = stub_sec->contents + stub_entry->stub_offset;
+
+  stub_bfd = stub_sec->owner;
+
+  /* Create the trampoline call stub:
+
+     pshb
+     ldab #%page(symbol)
+     ldy #%addr(symbol)
+     jmp __trampoline
+
+  */
+  sym_value = (stub_entry->target_value
+               + stub_entry->target_section->output_offset
+               + stub_entry->target_section->output_section->vma);
+  phys_addr = m68hc11_phys_addr (&htab->pinfo, sym_value);
+  phys_page = m68hc11_phys_page (&htab->pinfo, sym_value);
+
+  /* pshb; ldab #%page(sym) */
+  bfd_put_8 (stub_bfd, 0x37, loc);
+  bfd_put_8 (stub_bfd, 0xC6, loc + 1);
+  bfd_put_8 (stub_bfd, phys_page, loc + 2);
+  loc += 3;
+
+  /* ldy #%addr(sym)  */
+  bfd_put_8 (stub_bfd, 0x18, loc);
+  bfd_put_8 (stub_bfd, 0xCE, loc + 1);
+  bfd_put_16 (stub_bfd, phys_addr, loc + 2);
+  loc += 4;
+
+  /* jmp __trampoline  */
+  bfd_put_8 (stub_bfd, 0x7E, loc);
+  bfd_put_16 (stub_bfd, htab->pinfo.trampoline_addr, loc + 1);
 
-  return NULL;
+  return TRUE;
 }
 
+/* As above, but don't actually build the stub.  Just bump offset so
+   we know stub section sizes.  */
+
 static bfd_boolean
-elf32_m68hc11_gc_sweep_hook (abfd, info, sec, relocs)
-     bfd *abfd ATTRIBUTE_UNUSED;
-     struct bfd_link_info *info ATTRIBUTE_UNUSED;
-     asection *sec ATTRIBUTE_UNUSED;
-     const Elf_Internal_Rela *relocs ATTRIBUTE_UNUSED;
+m68hc11_elf_size_one_stub (gen_entry, in_arg)
+     struct bfd_hash_entry *gen_entry;
+     PTR in_arg ATTRIBUTE_UNUSED;
 {
-  /* We don't use got and plt entries for 68hc11/68hc12.  */
+  struct elf32_m68hc11_stub_hash_entry *stub_entry;
+
+  /* Massage our args to the form they really have.  */
+  stub_entry = (struct elf32_m68hc11_stub_hash_entry *) gen_entry;
+
+  stub_entry->stub_sec->_raw_size += 10;
   return TRUE;
 }
 
+/* Create a 68HC11 ELF linker hash table.  */
+
+static struct bfd_link_hash_table *
+m68hc11_elf_bfd_link_hash_table_create (abfd)
+     bfd *abfd;
+{
+  struct m68hc11_elf_link_hash_table *ret;
+
+  ret = m68hc11_elf_hash_table_create (abfd);
+  if (ret == (struct m68hc11_elf_link_hash_table *) NULL)
+    return NULL;
+
+  ret->size_one_stub = m68hc11_elf_size_one_stub;
+  ret->build_one_stub = m68hc11_elf_build_one_stub;
+
+  return &ret->root.root;
+}
+
 
 /* 68HC11 Linker Relaxation.  */
 
@@ -1251,365 +1280,7 @@ m68hc11_elf_relax_delete_bytes (abfd, se
     }
 }
 
-/* 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 bfd_boolean
-elf32_m68hc11_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;
-  struct elf_link_hash_entry ** 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_M68HC11_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_M68HC11_GNU_VTENTRY:
-          if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_addend))
-            return FALSE;
-          break;
-        }
-    }
-
-  return TRUE;
-}
-
-/* Relocate a 68hc11/68hc12 ELF section.  */
-static bfd_boolean
-elf32_m68hc11_relocate_section (output_bfd, info, input_bfd, input_section,
-                                contents, relocs, local_syms, local_sections)
-     bfd *output_bfd ATTRIBUTE_UNUSED;
-     struct bfd_link_info *info;
-     bfd *input_bfd;
-     asection *input_section;
-     bfd_byte *contents;
-     Elf_Internal_Rela *relocs;
-     Elf_Internal_Sym *local_syms;
-     asection **local_sections;
-{
-  Elf_Internal_Shdr *symtab_hdr;
-  struct elf_link_hash_entry **sym_hashes;
-  Elf_Internal_Rela *rel, *relend;
-  const char *name;
-
-  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
-  sym_hashes = elf_sym_hashes (input_bfd);
-
-  rel = relocs;
-  relend = relocs + input_section->reloc_count;
-  for (; rel < relend; rel++)
-    {
-      int r_type;
-      reloc_howto_type *howto;
-      unsigned long r_symndx;
-      Elf_Internal_Sym *sym;
-      asection *sec;
-      struct elf_link_hash_entry *h;
-      bfd_vma relocation;
-      bfd_reloc_status_type r;
-
-      r_symndx = ELF32_R_SYM (rel->r_info);
-      r_type = ELF32_R_TYPE (rel->r_info);
-
-      if (r_type == R_M68HC11_GNU_VTENTRY
-          || r_type == R_M68HC11_GNU_VTINHERIT )
-        continue;
-
-      howto = elf_m68hc11_howto_table + r_type;
-
-      if (info->relocateable)
-	{
-	  /* This is a relocateable link.  We don't have to change
-	     anything, unless the reloc is against a section symbol,
-	     in which case we have to adjust according to where the
-	     section symbol winds up in the output section.  */
-	  if (r_symndx < symtab_hdr->sh_info)
-	    {
-	      sym = local_syms + r_symndx;
-	      if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
-		{
-		  sec = local_sections[r_symndx];
-		  rel->r_addend += sec->output_offset + sym->st_value;
-		}
-	    }
-
-	  continue;
-	}
-
-      /* This is a final link.  */
-      h = NULL;
-      sym = NULL;
-      sec = NULL;
-      if (r_symndx < symtab_hdr->sh_info)
-	{
-	  sym = local_syms + r_symndx;
-	  sec = local_sections[r_symndx];
-	  relocation = (sec->output_section->vma
-			+ sec->output_offset
-			+ sym->st_value);
-	}
-      else
-	{
-	  h = sym_hashes[r_symndx - symtab_hdr->sh_info];
-	  while (h->root.type == bfd_link_hash_indirect
-		 || h->root.type == bfd_link_hash_warning)
-	    h = (struct elf_link_hash_entry *) h->root.u.i.link;
-	  if (h->root.type == bfd_link_hash_defined
-	      || h->root.type == bfd_link_hash_defweak)
-	    {
-	      sec = h->root.u.def.section;
-	      relocation = (h->root.u.def.value
-			    + sec->output_section->vma
-			    + sec->output_offset);
-	    }
-	  else if (h->root.type == bfd_link_hash_undefweak)
-	    relocation = 0;
-	  else
-	    {
-	      if (!((*info->callbacks->undefined_symbol)
-		    (info, h->root.root.string, input_bfd,
-		     input_section, rel->r_offset, TRUE)))
-		return FALSE;
-	      relocation = 0;
-	    }
-	}
-
-      if (h != NULL)
-	name = h->root.root.string;
-      else
-	{
-	  name = (bfd_elf_string_from_elf_section
-		  (input_bfd, symtab_hdr->sh_link, sym->st_name));
-	  if (name == NULL || *name == '\0')
-	    name = bfd_section_name (input_bfd, sec);
-	}
-
-      r = _bfd_final_link_relocate (howto, input_bfd, input_section,
-                                    contents, rel->r_offset,
-                                    relocation, rel->r_addend);
-
-      if (r != bfd_reloc_ok)
-	{
-	  const char * msg = (const char *) 0;
-
-	  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;
-	      break;
-
-	    case bfd_reloc_undefined:
-	      if (!((*info->callbacks->undefined_symbol)
-		    (info, name, input_bfd, input_section,
-		     rel->r_offset, TRUE)))
-		return FALSE;
-	      break;
-
-	    case bfd_reloc_outofrange:
-	      msg = _ ("internal error: out of range error");
-	      goto common_error;
-
-	    case bfd_reloc_notsupported:
-	      msg = _ ("internal error: unsupported relocation error");
-	      goto common_error;
-
-	    case bfd_reloc_dangerous:
-	      msg = _ ("internal error: dangerous error");
-	      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;
-	    }
-	}
-    }
-
-  return TRUE;
-}
-
-
 
-/* Set and control ELF flags in ELF header.  */
-
-bfd_boolean
-_bfd_m68hc11_elf_set_private_flags (abfd, flags)
-     bfd *abfd;
-     flagword flags;
-{
-  BFD_ASSERT (!elf_flags_init (abfd)
-	      || elf_elfheader (abfd)->e_flags == flags);
-
-  elf_elfheader (abfd)->e_flags = flags;
-  elf_flags_init (abfd) = TRUE;
-  return TRUE;
-}
-
-/* Merge backend specific data from an object file to the output
-   object file when linking.  */
-
-bfd_boolean
-_bfd_m68hc11_elf_merge_private_bfd_data (ibfd, obfd)
-     bfd *ibfd;
-     bfd *obfd;
-{
-  flagword old_flags;
-  flagword new_flags;
-  bfd_boolean ok = TRUE;
-
-  /* Check if we have the same endianess */
-  if (!_bfd_generic_verify_endian_match (ibfd, obfd))
-    return FALSE;
-
-  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;
-  elf_elfheader (obfd)->e_flags |= new_flags & EF_M68HC11_ABI;
-  old_flags = elf_elfheader (obfd)->e_flags;
-
-  if (! elf_flags_init (obfd))
-    {
-      elf_flags_init (obfd) = TRUE;
-      elf_elfheader (obfd)->e_flags = new_flags;
-      elf_elfheader (obfd)->e_ident[EI_CLASS]
-	= elf_elfheader (ibfd)->e_ident[EI_CLASS];
-
-      if (bfd_get_arch (obfd) == bfd_get_arch (ibfd)
-	  && bfd_get_arch_info (obfd)->the_default)
-	{
-	  if (! bfd_set_arch_mach (obfd, bfd_get_arch (ibfd),
-				   bfd_get_mach (ibfd)))
-	    return FALSE;
-	}
-
-      return TRUE;
-    }
-
-  /* Check ABI compatibility.  */
-  if ((new_flags & E_M68HC11_I32) != (old_flags & E_M68HC11_I32))
-    {
-      (*_bfd_error_handler)
-	(_("%s: linking files compiled for 16-bit integers (-mshort) "
-           "and others for 32-bit integers"),
-	 bfd_archive_filename (ibfd));
-      ok = FALSE;
-    }
-  if ((new_flags & E_M68HC11_F64) != (old_flags & E_M68HC11_F64))
-    {
-      (*_bfd_error_handler)
-	(_("%s: linking files compiled for 32-bit double (-fshort-double) "
-           "and others for 64-bit double"),
-	 bfd_archive_filename (ibfd));
-      ok = FALSE;
-    }
-  new_flags &= ~EF_M68HC11_ABI;
-  old_flags &= ~EF_M68HC11_ABI;
-
-  /* Warn about any other mismatches */
-  if (new_flags != old_flags)
-    {
-      (*_bfd_error_handler)
-	(_("%s: uses different e_flags (0x%lx) fields than previous modules (0x%lx)"),
-	 bfd_archive_filename (ibfd), (unsigned long) new_flags,
-	 (unsigned long) old_flags);
-      ok = FALSE;
-    }
-
-  if (! ok)
-    {
-      bfd_set_error (bfd_error_bad_value);
-      return FALSE;
-    }
-
-  return TRUE;
-}
-
-bfd_boolean
-_bfd_m68hc11_elf_print_private_bfd_data (abfd, ptr)
-     bfd *abfd;
-     PTR ptr;
-{
-  FILE *file = (FILE *) ptr;
-
-  BFD_ASSERT (abfd != NULL && ptr != NULL);
-
-  /* Print normal ELF private data.  */
-  _bfd_elf_print_private_bfd_data (abfd, ptr);
-
-  /* xgettext:c-format */
-  fprintf (file, _("private flags = %lx:"), elf_elfheader (abfd)->e_flags);
-
-  if (elf_elfheader (abfd)->e_flags & E_M68HC11_I32)
-    fprintf (file, _("[abi=32-bit int,"));
-  else
-    fprintf (file, _("[abi=16-bit int,"));
-
-  if (elf_elfheader (abfd)->e_flags & E_M68HC11_F64)
-    fprintf (file, _(" 64-bit double]"));
-  else
-    fprintf (file, _(" 32-bit double]"));
-
-  if (elf_elfheader (abfd)->e_flags & E_M68HC12_BANKS)
-    fprintf (file, _(" [memory=bank-model]"));
-  else
-    fprintf (file, _(" [memory=flat]"));
-
-  fputc ('\n', file);
-
-  return TRUE;
-}
-
-/* Below is the only difference between elf32-m68hc12.c and elf32-m68hc11.c.
-   The Motorola spec says to use a different Elf machine code.  */
 #define ELF_ARCH		bfd_arch_m68hc11
 #define ELF_MACHINE_CODE	EM_68HC11
 #define ELF_MAXPAGESIZE		0x1000
@@ -1624,9 +1295,15 @@ _bfd_m68hc11_elf_print_private_bfd_data 
 #define elf_backend_gc_sweep_hook    elf32_m68hc11_gc_sweep_hook
 #define elf_backend_check_relocs     elf32_m68hc11_check_relocs
 #define elf_backend_relocate_section elf32_m68hc11_relocate_section
+#define elf_backend_add_symbol_hook  elf32_m68hc11_add_symbol_hook
 #define elf_backend_object_p	0
 #define elf_backend_final_write_processing	0
 #define elf_backend_can_gc_sections		1
+
+#define bfd_elf32_bfd_link_hash_table_create \
+                                m68hc11_elf_bfd_link_hash_table_create
+#define bfd_elf32_bfd_link_hash_table_free \
+				m68hc11_elf_bfd_link_hash_table_free
 #define bfd_elf32_bfd_merge_private_bfd_data \
 					_bfd_m68hc11_elf_merge_private_bfd_data
 #define bfd_elf32_bfd_set_private_flags	_bfd_m68hc11_elf_set_private_flags
Index: elf32-m68hc12.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-m68hc12.c,v
retrieving revision 1.13
diff -u -p -r1.13 elf32-m68hc12.c
--- elf32-m68hc12.c	8 Dec 2002 03:34:38 -0000	1.13
+++ elf32-m68hc12.c	19 Apr 2003 08:54:54 -0000
@@ -1,5 +1,5 @@
 /* Motorola 68HC12-specific support for 32-bit ELF
-   Copyright 1999, 2000, 2002 Free Software Foundation, Inc.
+   Copyright 1999, 2000, 2002, 2003 Free Software Foundation, Inc.
    Contributed by Stephane Carrez (stcarrez at nerim dot fr)
    (Heavily copied from the D10V port by Martin Hunt (hunt at cygnus dot com))
 
@@ -21,49 +21,33 @@ Foundation, Inc., 59 Temple Place - Suit
 
 #include "bfd.h"
 #include "sysdep.h"
+#include "bfdlink.h"
 #include "libbfd.h"
 #include "elf-bfd.h"
+#include "elf32-m68hc1x.h"
 #include "elf/m68hc11.h"
 #include "opcode/m68hc11.h"
 
+/* Relocation functions.  */
 static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup
   PARAMS ((bfd *, bfd_reloc_code_real_type));
 static void m68hc11_info_to_howto_rel
   PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
 
-static bfd_reloc_status_type m68hc11_elf_ignore_reloc
-  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
-static bfd_reloc_status_type m68hc12_elf_special_reloc
-  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
-static int m68hc12_addr_is_banked PARAMS ((bfd_vma));
-static bfd_vma m68hc12_phys_addr PARAMS ((bfd_vma));
-static bfd_vma m68hc12_phys_page PARAMS ((bfd_vma));
-
-/* GC mark and sweep.  */
-static asection *elf32_m68hc11_gc_mark_hook
-  PARAMS ((asection *, struct bfd_link_info *, Elf_Internal_Rela *,
-	   struct elf_link_hash_entry *, Elf_Internal_Sym *));
-static bfd_boolean elf32_m68hc11_gc_sweep_hook
-  PARAMS ((bfd *, struct bfd_link_info *, asection *,
-	   const Elf_Internal_Rela *));
+/* Trampoline generation.  */
+static bfd_boolean m68hc12_elf_size_one_stub
+  PARAMS((struct bfd_hash_entry *gen_entry, PTR in_arg));
+static bfd_boolean m68hc12_elf_build_one_stub
+  PARAMS((struct bfd_hash_entry *gen_entry, PTR in_arg));
+static struct bfd_link_hash_table* m68hc12_elf_bfd_link_hash_table_create
+  PARAMS((bfd*));
 
 static bfd_boolean m68hc12_elf_set_mach_from_flags PARAMS ((bfd *));
 
-bfd_boolean _bfd_m68hc12_elf_merge_private_bfd_data PARAMS ((bfd *, bfd *));
-bfd_boolean _bfd_m68hc12_elf_set_private_flags PARAMS ((bfd *, flagword));
-bfd_boolean _bfd_m68hc12_elf_print_private_bfd_data PARAMS ((bfd *, PTR));
-
-
-
 /* Use REL instead of RELA to save space */
 #define USE_REL	1
 
-/* The Motorola 68HC11 microcontroler only addresses 64Kb.
-   We must handle 8 and 16-bit relocations.  The 32-bit relocation
-   is defined but not used except by gas when -gstabs is used (which
-   is wrong).
-
-   The 68HC12 microcontroler has a memory bank switching system
+/* The 68HC12 microcontroler has a memory bank switching system
    with a 16Kb window in the 64Kb address space.  The extended memory
    is mapped in the 16Kb window (at 0x8000).  The page register controls
    which 16Kb bank is mapped.  The call/rtc instructions take care of
@@ -199,7 +183,7 @@ static reloc_howto_type elf_m68hc11_howt
 	 FALSE,			/* partial_inplace */
 	 0x00ff,		/* src_mask */
 	 0x00ff,		/* dst_mask */
-	 FALSE),		/* pcrel_offset */
+	 TRUE),                 /* pcrel_offset */
 
   /* A 16 bit absolute relocation */
   HOWTO (R_M68HC11_16,		/* type */
@@ -209,7 +193,7 @@ static reloc_howto_type elf_m68hc11_howt
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
 	 complain_overflow_dont /*bitfield */ ,	/* complain_on_overflow */
-	 m68hc12_elf_special_reloc,	/* special_function */
+	 bfd_elf_generic_reloc,	/* special_function */
 	 "R_M68HC12_16",	/* name */
 	 FALSE,			/* partial_inplace */
 	 0xffff,		/* src_mask */
@@ -260,7 +244,7 @@ static reloc_howto_type elf_m68hc11_howt
 	 FALSE,			/* partial_inplace */
 	 0xffff,		/* src_mask */
 	 0xffff,		/* dst_mask */
-	 FALSE),		/* pcrel_offset */
+	 TRUE),                 /* pcrel_offset */
 
   /* GNU extension to record C++ vtable hierarchy */
   HOWTO (R_M68HC11_GNU_VTINHERIT,	/* type */
@@ -295,16 +279,16 @@ static reloc_howto_type elf_m68hc11_howt
   /* A 24 bit relocation */
   HOWTO (R_M68HC11_24,	        /* type */
 	 0,			/* rightshift */
-	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
 	 24,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
 	 complain_overflow_dont,	/* complain_on_overflow */
-	 m68hc12_elf_special_reloc,	/* special_function */
+	 m68hc11_elf_special_reloc,	/* special_function */
 	 "R_M68HC12_24",	/* name */
 	 FALSE,			/* partial_inplace */
-	 0xffff,		/* src_mask */
-	 0xffff,		/* dst_mask */
+	 0xffffff,		/* src_mask */
+	 0xffffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
   /* A 16-bit low relocation */
@@ -315,7 +299,7 @@ static reloc_howto_type elf_m68hc11_howt
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
 	 complain_overflow_dont,	/* complain_on_overflow */
-	 m68hc12_elf_special_reloc,/* special_function */
+	 m68hc11_elf_special_reloc,/* special_function */
 	 "R_M68HC12_LO16",	/* name */
 	 FALSE,			/* partial_inplace */
 	 0xffff,		/* src_mask */
@@ -330,7 +314,7 @@ static reloc_howto_type elf_m68hc11_howt
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
 	 complain_overflow_dont,	/* complain_on_overflow */
-	 m68hc12_elf_special_reloc,/* special_function */
+	 m68hc11_elf_special_reloc,/* special_function */
 	 "R_M68HC12_PAGE",	/* name */
 	 FALSE,			/* partial_inplace */
 	 0x00ff,		/* src_mask */
@@ -423,158 +407,6 @@ bfd_elf32_bfd_reloc_type_lookup (abfd, c
   return NULL;
 }
 
-/* This function is used for relocs which are only used for relaxing,
-   which the linker should otherwise ignore.  */
-
-static bfd_reloc_status_type
-m68hc11_elf_ignore_reloc (abfd, reloc_entry, symbol, data, input_section,
-                          output_bfd, error_message)
-     bfd *abfd ATTRIBUTE_UNUSED;
-     arelent *reloc_entry;
-     asymbol *symbol ATTRIBUTE_UNUSED;
-     PTR data ATTRIBUTE_UNUSED;
-     asection *input_section;
-     bfd *output_bfd;
-     char **error_message ATTRIBUTE_UNUSED;
-{
-  if (output_bfd != NULL)
-    reloc_entry->address += input_section->output_offset;
-  return bfd_reloc_ok;
-}
-
-static int
-m68hc12_addr_is_banked (addr)
-     bfd_vma addr;
-{
-   return (addr >= M68HC12_BANK_VIRT) ? 1 : 0;
-}
-
-/* Return the physical address seen by the processor, taking
-   into account banked memory.  */
-static bfd_vma
-m68hc12_phys_addr (addr)
-     bfd_vma addr;
-{
-  if (addr < M68HC12_BANK_VIRT)
-    return addr;
-
-  /* Map the address to the memory bank.  */
-  addr -= M68HC12_BANK_VIRT;
-  addr &= M68HC12_BANK_MASK;
-  addr += M68HC12_BANK_BASE;
-  return addr;
-}
-
-/* Return the page number corresponding to an address in banked memory.  */
-static bfd_vma
-m68hc12_phys_page (addr)
-     bfd_vma addr;
-{
-  if (addr < M68HC12_BANK_VIRT)
-    return 0;
-
-  /* Map the address to the memory bank.  */
-  addr -= M68HC12_BANK_VIRT;
-  addr >>= M68HC12_BANK_SHIFT;
-  addr &= M68HC12_BANK_PAGE_MASK;
-  return addr;
-}
-
-static bfd_reloc_status_type
-m68hc12_elf_special_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 ATTRIBUTE_UNUSED;
-{
-  reloc_howto_type *howto;
-  bfd_vma relocation;
-  bfd_vma phys_addr;
-  bfd_vma phys_page;
-  bfd_vma insn_page;
-  bfd_vma insn_addr;
-
-  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)
-    return bfd_reloc_continue;
-
-  if (reloc_entry->address > input_section->_cooked_size)
-    return bfd_reloc_outofrange;
-
-  /* Compute relocation.  */
-  relocation = (symbol->value
-		+ symbol->section->output_section->vma
-		+ symbol->section->output_offset);
-  relocation += reloc_entry->addend;
-  relocation += bfd_get_16 (abfd, (bfd_byte*) data + reloc_entry->address);
-
-  /* Do the memory bank mapping.  */
-  phys_addr = m68hc12_phys_addr (relocation);
-  phys_page = m68hc12_phys_page (relocation);
-
-  howto = reloc_entry->howto;
-  if (howto->complain_on_overflow != complain_overflow_dont
-      && (phys_addr & (((bfd_vma) -1) << 16)))
-     return bfd_reloc_overflow;
-
-  switch (howto->type)
-    {
-    case R_M68HC11_16:
-          /* Get virtual address of instruction having the relocation.  */
-       insn_addr = input_section->output_section->vma
-          + input_section->output_offset
-          + reloc_entry->address;
-
-      insn_page = m68hc12_phys_page (insn_addr);
-
-      if (m68hc12_addr_is_banked (relocation)
-          && m68hc12_addr_is_banked (insn_addr)
-          && phys_page != insn_page)
-         {
-            *error_message = _("address is not in the same bank");
-            return bfd_reloc_dangerous;
-         }
-      if (m68hc12_addr_is_banked (relocation)
-          && !m68hc12_addr_is_banked (insn_addr))
-         {
-            *error_message = _("reference to a banked address in "
-                               "the normal address space");
-            return bfd_reloc_dangerous;
-         }
-
-    case R_M68HC11_LO16:
-      bfd_put_16 (abfd, phys_addr, (bfd_byte*) data + reloc_entry->address);
-      break;
-
-    case R_M68HC11_24:
-      bfd_put_16 (abfd, phys_addr, (bfd_byte*) data + reloc_entry->address);
-      bfd_put_8 (abfd, phys_page, (bfd_byte*) data + reloc_entry->address + 2);
-      break;
-
-    case R_M68HC11_PAGE:
-      bfd_put_8 (abfd, phys_page, (bfd_byte*) data + reloc_entry->address);
-      break;
-
-    default:
-       abort ();
-       break;
-    }
-
-  return bfd_reloc_ok;
-}
-
 /* Set the howto pointer for an M68HC11 ELF reloc.  */
 
 static void
@@ -590,50 +422,97 @@ m68hc11_info_to_howto_rel (abfd, cache_p
   cache_ptr->howto = &elf_m68hc11_howto_table[r_type];
 }
 
-static asection *
-elf32_m68hc11_gc_mark_hook (sec, info, rel, h, sym)
-     asection *sec;
-     struct bfd_link_info *info ATTRIBUTE_UNUSED;
-     Elf_Internal_Rela *rel;
-     struct elf_link_hash_entry *h;
-     Elf_Internal_Sym *sym;
-{
-  if (h != NULL)
-    {
-      switch (ELF32_R_TYPE (rel->r_info))
-	{
-	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
-    return bfd_section_from_elf_index (sec->owner, sym->st_shndx);
+
+/* Far trampoline generation.  */
 
-  return NULL;
+/* Build a 68HC12 trampoline stub.  */
+static bfd_boolean
+m68hc12_elf_build_one_stub (gen_entry, in_arg)
+     struct bfd_hash_entry *gen_entry;
+     PTR in_arg;
+{
+  struct elf32_m68hc11_stub_hash_entry *stub_entry;
+  struct bfd_link_info *info;
+  struct m68hc11_elf_link_hash_table *htab;
+  asection *stub_sec;
+  bfd *stub_bfd;
+  bfd_byte *loc;
+  bfd_vma sym_value, phys_page, phys_addr;
+
+  /* Massage our args to the form they really have.  */
+  stub_entry = (struct elf32_m68hc11_stub_hash_entry *) gen_entry;
+  info = (struct bfd_link_info *) in_arg;
+
+  htab = m68hc11_elf_hash_table (info);
+
+  stub_sec = stub_entry->stub_sec;
+
+  /* Make a note of the offset within the stubs for this entry.  */
+  stub_entry->stub_offset = stub_sec->_raw_size;
+  stub_sec->_raw_size += 7;
+  loc = stub_sec->contents + stub_entry->stub_offset;
+
+  stub_bfd = stub_sec->owner;
+
+  /* Create the trampoline call stub:
+
+     ldy #%addr(symbol)
+     call %page(symbol), __trampoline
+
+  */
+  sym_value = (stub_entry->target_value
+               + stub_entry->target_section->output_offset
+               + stub_entry->target_section->output_section->vma);
+  phys_addr = m68hc11_phys_addr (&htab->pinfo, sym_value);
+  phys_page = m68hc11_phys_page (&htab->pinfo, sym_value);
+
+  /* ldy #%page(sym) */
+  bfd_put_8 (stub_bfd, 0xCD, loc);
+  bfd_put_16 (stub_bfd, phys_addr, loc + 1);
+  loc += 3;
+
+  /* call %page(sym), __trampoline  */
+  bfd_put_8 (stub_bfd, 0x4a, loc);
+  bfd_put_16 (stub_bfd, htab->pinfo.trampoline_addr, loc + 1);
+  bfd_put_8 (stub_bfd, phys_page, loc + 3);
+
+  return TRUE;
 }
 
+/* As above, but don't actually build the stub.  Just bump offset so
+   we know stub section sizes.  */
+
 static bfd_boolean
-elf32_m68hc11_gc_sweep_hook (abfd, info, sec, relocs)
-     bfd *abfd ATTRIBUTE_UNUSED;
-     struct bfd_link_info *info ATTRIBUTE_UNUSED;
-     asection *sec ATTRIBUTE_UNUSED;
-     const Elf_Internal_Rela *relocs ATTRIBUTE_UNUSED;
+m68hc12_elf_size_one_stub (gen_entry, in_arg)
+     struct bfd_hash_entry *gen_entry;
+     PTR in_arg ATTRIBUTE_UNUSED;
 {
-  /* We don't use got and plt entries for 68hc11/68hc12.  */
+  struct elf32_m68hc11_stub_hash_entry *stub_entry;
+
+  /* Massage our args to the form they really have.  */
+  stub_entry = (struct elf32_m68hc11_stub_hash_entry *) gen_entry;
+
+  stub_entry->stub_sec->_raw_size += 7;
   return TRUE;
 }
 
+/* Create a 68HC12 ELF linker hash table.  */
+
+static struct bfd_link_hash_table *
+m68hc12_elf_bfd_link_hash_table_create (abfd)
+     bfd *abfd;
+{
+  struct m68hc11_elf_link_hash_table *ret;
+
+  ret = m68hc11_elf_hash_table_create (abfd);
+  if (ret == (struct m68hc11_elf_link_hash_table *) NULL)
+    return NULL;
+
+  ret->size_one_stub = m68hc12_elf_size_one_stub;
+  ret->build_one_stub = m68hc12_elf_build_one_stub;
+
+  return &ret->root.root;
+}
 
 static bfd_boolean
 m68hc12_elf_set_mach_from_flags (abfd)
@@ -659,149 +538,6 @@ m68hc12_elf_set_mach_from_flags (abfd)
   return TRUE;
 }
 
-/* Set and control ELF flags in ELF header.  */
-
-bfd_boolean
-_bfd_m68hc12_elf_set_private_flags (abfd, flags)
-     bfd *abfd;
-     flagword flags;
-{
-  BFD_ASSERT (!elf_flags_init (abfd)
-	      || elf_elfheader (abfd)->e_flags == flags);
-
-  elf_elfheader (abfd)->e_flags = flags;
-  elf_flags_init (abfd) = TRUE;
-  return m68hc12_elf_set_mach_from_flags (abfd);
-}
-
-/* Merge backend specific data from an object file to the output
-   object file when linking.  */
-
-bfd_boolean
-_bfd_m68hc12_elf_merge_private_bfd_data (ibfd, obfd)
-     bfd *ibfd;
-     bfd *obfd;
-{
-  flagword old_flags;
-  flagword new_flags;
-  bfd_boolean ok = TRUE;
-
-  /* Check if we have the same endianess */
-  if (!_bfd_generic_verify_endian_match (ibfd, obfd))
-    return FALSE;
-
-  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;
-
-  if (! elf_flags_init (obfd))
-    {
-      elf_flags_init (obfd) = TRUE;
-      elf_elfheader (obfd)->e_flags = new_flags;
-      elf_elfheader (obfd)->e_ident[EI_CLASS]
-	= elf_elfheader (ibfd)->e_ident[EI_CLASS];
-
-      if (bfd_get_arch (obfd) == bfd_get_arch (ibfd)
-	  && bfd_get_arch_info (obfd)->the_default)
-	{
-	  if (! bfd_set_arch_mach (obfd, bfd_get_arch (ibfd),
-				   bfd_get_mach (ibfd)))
-	    return FALSE;
-	}
-
-      return TRUE;
-    }
-
-  /* Check ABI compatibility.  */
-  if ((new_flags & E_M68HC11_I32) != (old_flags & E_M68HC11_I32))
-    {
-      (*_bfd_error_handler)
-	(_("%s: linking files compiled for 16-bit integers (-mshort) "
-           "and others for 32-bit integers"),
-	 bfd_archive_filename (ibfd));
-      ok = FALSE;
-    }
-  if ((new_flags & E_M68HC11_F64) != (old_flags & E_M68HC11_F64))
-    {
-      (*_bfd_error_handler)
-	(_("%s: linking files compiled for 32-bit double (-fshort-double) "
-           "and others for 64-bit double"),
-	 bfd_archive_filename (ibfd));
-      ok = FALSE;
-    }
-
-  /* Processor compatibility.  */
-  if (!EF_M68HC11_CAN_MERGE_MACH (new_flags, old_flags))
-    {
-      (*_bfd_error_handler)
-	(_("%s: linking files compiled for HCS12 with "
-           "others compiled for HC12"),
-	 bfd_archive_filename (ibfd));
-      ok = FALSE;
-    }
-  new_flags = ((new_flags & ~EF_M68HC11_MACH_MASK)
-               | (EF_M68HC11_MERGE_MACH (new_flags, old_flags)));
-
-  elf_elfheader (obfd)->e_flags = new_flags;
-
-  /* Warn about any other mismatches */
-  new_flags &= ~(EF_M68HC11_ABI | EF_M68HC11_MACH_MASK);
-  old_flags &= ~(EF_M68HC11_ABI | EF_M68HC11_MACH_MASK);
-  if (new_flags != old_flags)
-    {
-      (*_bfd_error_handler)
-	(_("%s: uses different e_flags (0x%lx) fields than previous modules (0x%lx)"),
-	 bfd_archive_filename (ibfd), (unsigned long) new_flags,
-	 (unsigned long) old_flags);
-      ok = FALSE;
-    }
-
-  if (! ok)
-    {
-      bfd_set_error (bfd_error_bad_value);
-      return FALSE;
-    }
-
-  return TRUE;
-}
-
-bfd_boolean
-_bfd_m68hc12_elf_print_private_bfd_data (abfd, ptr)
-     bfd *abfd;
-     PTR ptr;
-{
-  FILE *file = (FILE *) ptr;
-
-  BFD_ASSERT (abfd != NULL && ptr != NULL);
-
-  /* Print normal ELF private data.  */
-  _bfd_elf_print_private_bfd_data (abfd, ptr);
-
-  /* xgettext:c-format */
-  fprintf (file, _("private flags = %lx:"), elf_elfheader (abfd)->e_flags);
-
-  if (elf_elfheader (abfd)->e_flags & E_M68HC11_I32)
-    fprintf (file, _("[abi=32-bit int,"));
-  else
-    fprintf (file, _("[abi=16-bit int,"));
-
-  if (elf_elfheader (abfd)->e_flags & E_M68HC11_F64)
-    fprintf (file, _(" 64-bit double,"));
-  else
-    fprintf (file, _(" 32-bit double,"));
-
-  if (elf_elfheader (abfd)->e_flags & EF_M68HCS12_MACH)
-    fprintf (file, _(" cpu=HCS12]"));
-  else
-    fprintf (file, _(" cpu=HC12]"));
-  fputc ('\n', file);
-
-  return TRUE;
-}
-
 #define ELF_ARCH		bfd_arch_m68hc12
 #define ELF_MACHINE_CODE	EM_68HC12
 #define ELF_MAXPAGESIZE		0x1000
@@ -813,15 +549,22 @@ _bfd_m68hc12_elf_print_private_bfd_data 
 #define elf_info_to_howto_rel	m68hc11_info_to_howto_rel
 #define elf_backend_gc_mark_hook     elf32_m68hc11_gc_mark_hook
 #define elf_backend_gc_sweep_hook    elf32_m68hc11_gc_sweep_hook
+#define elf_backend_check_relocs     elf32_m68hc11_check_relocs
+#define elf_backend_relocate_section elf32_m68hc11_relocate_section
 #define elf_backend_object_p		m68hc12_elf_set_mach_from_flags
 #define elf_backend_final_write_processing	0
-/* Disabled as this backend uses the generic linker.  */
-#define elf_backend_can_gc_sections		0
-
+#define elf_backend_can_gc_sections		1
+#define elf_backend_post_process_headers     elf32_m68hc11_post_process_headers
+#define elf_backend_add_symbol_hook  elf32_m68hc11_add_symbol_hook
+
+#define bfd_elf32_bfd_link_hash_table_create \
+                                m68hc12_elf_bfd_link_hash_table_create
+#define bfd_elf32_bfd_link_hash_table_free \
+				m68hc11_elf_bfd_link_hash_table_free
 #define bfd_elf32_bfd_merge_private_bfd_data \
-					_bfd_m68hc12_elf_merge_private_bfd_data
-#define bfd_elf32_bfd_set_private_flags	_bfd_m68hc12_elf_set_private_flags
+					_bfd_m68hc11_elf_merge_private_bfd_data
+#define bfd_elf32_bfd_set_private_flags	_bfd_m68hc11_elf_set_private_flags
 #define bfd_elf32_bfd_print_private_bfd_data \
-					_bfd_m68hc12_elf_print_private_bfd_data
+					_bfd_m68hc11_elf_print_private_bfd_data
 
 #include "elf32-target.h"
Index: elf32-m68hc1x.c
===================================================================
RCS file: elf32-m68hc1x.c
diff -N elf32-m68hc1x.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ elf32-m68hc1x.c	19 Apr 2003 08:54:55 -0000
@@ -0,0 +1,1508 @@
+/* Motorola 68HC11/HC12-specific support for 32-bit ELF
+   Copyright 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   Contributed by Stephane Carrez (stcarrez at nerim dot fr)
+
+This file is part of BFD, the Binary File Descriptor library.
+
+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
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "bfdlink.h"
+#include "libbfd.h"
+#include "elf-bfd.h"
+#include "elf32-m68hc1x.h"
+#include "elf/m68hc11.h"
+#include "opcode/m68hc11.h"
+
+
+#define m68hc12_stub_hash_lookup(table, string, create, copy) \
+  ((struct elf32_m68hc11_stub_hash_entry *) \
+   bfd_hash_lookup ((table), (string), (create), (copy)))
+
+static struct elf32_m68hc11_stub_hash_entry* m68hc12_add_stub
+  PARAMS((const char *stub_name,
+          asection *section,
+          struct m68hc11_elf_link_hash_table *htab));
+
+static struct bfd_hash_entry *stub_hash_newfunc
+  PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
+
+static void m68hc11_elf_set_symbol
+  PARAMS ((bfd* abfd, struct bfd_link_info *info,
+           const char* name, bfd_vma value, asection* sec));
+
+static bfd_boolean m68hc11_elf_export_one_stub
+  PARAMS((struct bfd_hash_entry *gen_entry, PTR in_arg));
+
+static bfd_boolean m68hc11_get_relocation_value
+  PARAMS ((bfd* abfd,
+           struct bfd_link_info* info,
+           asection **local_sections,
+           Elf_Internal_Sym* local_syms,
+           Elf_Internal_Rela* rel,
+           const char** name,
+           bfd_vma* relocation,
+           bfd_boolean* is_far));
+
+static void scan_sections_for_abi PARAMS ((bfd*, asection*, PTR));
+
+struct m68hc11_scan_param
+{
+   struct m68hc11_page_info* pinfo;
+   bfd_boolean use_memory_banks;
+};
+
+
+/* Create a 68HC11/68HC12 ELF linker hash table.  */
+
+struct m68hc11_elf_link_hash_table*
+m68hc11_elf_hash_table_create (abfd)
+     bfd *abfd;
+{
+  struct m68hc11_elf_link_hash_table *ret;
+  bfd_size_type amt = sizeof (struct m68hc11_elf_link_hash_table);
+
+  ret = (struct m68hc11_elf_link_hash_table *) bfd_zalloc (abfd, amt);
+  if (ret == (struct m68hc11_elf_link_hash_table *) NULL)
+    return NULL;
+
+  if (! _bfd_elf_link_hash_table_init (&ret->root, abfd,
+				       _bfd_elf_link_hash_newfunc))
+    {
+      bfd_release (abfd, ret);
+      return NULL;
+    }
+
+  /* Init the stub hash table too.  */
+  amt = sizeof (struct bfd_hash_table);
+  ret->stub_hash_table = (struct bfd_hash_table*) bfd_malloc (amt);
+  if (ret->stub_hash_table == NULL)
+    {
+      bfd_release (abfd, ret);
+      return NULL;
+    }
+  if (!bfd_hash_table_init (ret->stub_hash_table, stub_hash_newfunc))
+    return NULL;
+
+  ret->stub_bfd = NULL;
+  ret->stub_section = 0;
+  ret->add_stub_section = NULL;
+  ret->sym_sec.abfd = NULL;
+
+  return ret;
+}
+
+/* Free the derived linker hash table.  */
+
+void
+m68hc11_elf_bfd_link_hash_table_free (hash)
+     struct bfd_link_hash_table *hash;
+{
+  struct m68hc11_elf_link_hash_table *ret
+    = (struct m68hc11_elf_link_hash_table *) hash;
+
+  bfd_hash_table_free (ret->stub_hash_table);
+  free (ret->stub_hash_table);
+  _bfd_generic_link_hash_table_free (hash);
+}
+
+/* Assorted hash table functions.  */
+
+/* Initialize an entry in the stub hash table.  */
+
+static struct bfd_hash_entry *
+stub_hash_newfunc (entry, table, string)
+     struct bfd_hash_entry *entry;
+     struct bfd_hash_table *table;
+     const char *string;
+{
+  /* Allocate the structure if it has not already been allocated by a
+     subclass.  */
+  if (entry == NULL)
+    {
+      entry = bfd_hash_allocate (table,
+				 sizeof (struct elf32_m68hc11_stub_hash_entry));
+      if (entry == NULL)
+	return entry;
+    }
+
+  /* Call the allocation method of the superclass.  */
+  entry = bfd_hash_newfunc (entry, table, string);
+  if (entry != NULL)
+    {
+      struct elf32_m68hc11_stub_hash_entry *eh;
+
+      /* Initialize the local fields.  */
+      eh = (struct elf32_m68hc11_stub_hash_entry *) entry;
+      eh->stub_sec = NULL;
+      eh->stub_offset = 0;
+      eh->target_value = 0;
+      eh->target_section = NULL;
+    }
+
+  return entry;
+}
+
+/* Add a new stub entry to the stub hash.  Not all fields of the new
+   stub entry are initialised.  */
+
+static struct elf32_m68hc11_stub_hash_entry *
+m68hc12_add_stub (stub_name, section, htab)
+     const char *stub_name;
+     asection *section;
+     struct m68hc11_elf_link_hash_table *htab;
+{
+  struct elf32_m68hc11_stub_hash_entry *stub_entry;
+
+  /* Enter this entry into the linker stub hash table.  */
+  stub_entry = m68hc12_stub_hash_lookup (htab->stub_hash_table, stub_name,
+                                         TRUE, FALSE);
+  if (stub_entry == NULL)
+    {
+      (*_bfd_error_handler) (_("%s: cannot create stub entry %s"),
+			     bfd_archive_filename (section->owner),
+			     stub_name);
+      return NULL;
+    }
+
+  if (htab->stub_section == 0)
+    {
+      htab->stub_section = (*htab->add_stub_section) (".tramp",
+                                                      htab->tramp_section);
+    }
+
+  stub_entry->stub_sec = htab->stub_section;
+  stub_entry->stub_offset = 0;
+  return stub_entry;
+}
+
+/* Hook called by the linker routine which adds symbols from an object
+   file.  We use it for identify far symbols and force a loading of
+   the trampoline handler.  */
+
+bfd_boolean
+elf32_m68hc11_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp)
+     bfd *abfd;
+     struct bfd_link_info *info;
+     const Elf_Internal_Sym *sym;
+     const char **namep ATTRIBUTE_UNUSED;
+     flagword *flagsp ATTRIBUTE_UNUSED;
+     asection **secp ATTRIBUTE_UNUSED;
+     bfd_vma *valp ATTRIBUTE_UNUSED;
+{
+  if (sym->st_other & STO_M68HC12_FAR)
+    {
+      struct elf_link_hash_entry *h;
+
+      h = (struct elf_link_hash_entry *)
+	bfd_link_hash_lookup (info->hash, "__far_trampoline",
+                              FALSE, FALSE, FALSE);
+      if (h == NULL)
+        {
+          struct bfd_link_hash_entry* entry = NULL;
+
+          _bfd_generic_link_add_one_symbol (info, abfd,
+                                            "__far_trampoline",
+                                            BSF_GLOBAL,
+                                            bfd_und_section_ptr,
+                                            (bfd_vma) 0, (const char*) NULL,
+                                            FALSE, FALSE, &entry);
+        }
+
+    }
+  return TRUE;
+}
+
+/* External entry points for sizing and building linker stubs.  */
+
+/* Set up various things so that we can make a list of input sections
+   for each output section included in the link.  Returns -1 on error,
+   0 when no stubs will be needed, and 1 on success.  */
+
+int
+elf32_m68hc11_setup_section_lists (output_bfd, info)
+     bfd *output_bfd;
+     struct bfd_link_info *info;
+{
+  bfd *input_bfd;
+  unsigned int bfd_count;
+  int top_id, top_index;
+  asection *section;
+  asection **input_list, **list;
+  bfd_size_type amt;
+  asection *text_section;
+  struct m68hc11_elf_link_hash_table *htab;
+
+  htab = m68hc11_elf_hash_table (info);
+
+  if (htab->root.root.creator->flavour != bfd_target_elf_flavour)
+    return 0;
+
+  /* Count the number of input BFDs and find the top input section id.
+     Also search for an existing ".tramp" section so that we know
+     where generated trampolines must go.  Default to ".text" if we
+     can't find it.  */
+  htab->tramp_section = 0;
+  text_section = 0;
+  for (input_bfd = info->input_bfds, bfd_count = 0, top_id = 0;
+       input_bfd != NULL;
+       input_bfd = input_bfd->link_next)
+    {
+      bfd_count += 1;
+      for (section = input_bfd->sections;
+	   section != NULL;
+	   section = section->next)
+	{
+          const char* name = bfd_get_section_name (input_bfd, section);
+
+          if (!strcmp (name, ".tramp"))
+            htab->tramp_section = section;
+
+          if (!strcmp (name, ".text"))
+            text_section = section;
+
+	  if (top_id < section->id)
+	    top_id = section->id;
+	}
+    }
+  htab->bfd_count = bfd_count;
+  if (htab->tramp_section == 0)
+    htab->tramp_section = text_section;
+
+  /* We can't use output_bfd->section_count here to find the top output
+     section index as some sections may have been removed, and
+     _bfd_strip_section_from_output doesn't renumber the indices.  */
+  for (section = output_bfd->sections, top_index = 0;
+       section != NULL;
+       section = section->next)
+    {
+      if (top_index < section->index)
+	top_index = section->index;
+    }
+
+  htab->top_index = top_index;
+  amt = sizeof (asection *) * (top_index + 1);
+  input_list = (asection **) bfd_malloc (amt);
+  htab->input_list = input_list;
+  if (input_list == NULL)
+    return -1;
+
+  /* For sections we aren't interested in, mark their entries with a
+     value we can check later.  */
+  list = input_list + top_index;
+  do
+    *list = bfd_abs_section_ptr;
+  while (list-- != input_list);
+
+  for (section = output_bfd->sections;
+       section != NULL;
+       section = section->next)
+    {
+      if ((section->flags & SEC_CODE) != 0)
+	input_list[section->index] = NULL;
+    }
+
+  return 1;
+}
+
+/* Determine and set the size of the stub section for a final link.
+
+   The basic idea here is to examine all the relocations looking for
+   PC-relative calls to a target that is unreachable with a "bl"
+   instruction.  */
+
+bfd_boolean
+elf32_m68hc11_size_stubs (output_bfd, stub_bfd, info, add_stub_section)
+     bfd *output_bfd;
+     bfd *stub_bfd;
+     struct bfd_link_info *info;
+     asection * (*add_stub_section) PARAMS ((const char *, asection *));
+{
+  bfd *input_bfd;
+  asection *section;
+  Elf_Internal_Sym *local_syms, **all_local_syms;
+  unsigned int bfd_indx, bfd_count;
+  bfd_size_type amt;
+  asection *stub_sec;
+
+  struct m68hc11_elf_link_hash_table *htab = m68hc11_elf_hash_table (info);
+
+  /* Stash our params away.  */
+  htab->stub_bfd = stub_bfd;
+  htab->add_stub_section = add_stub_section;
+
+  /* Count the number of input BFDs and find the top input section id.  */
+  for (input_bfd = info->input_bfds, bfd_count = 0;
+       input_bfd != NULL;
+       input_bfd = input_bfd->link_next)
+    {
+      bfd_count += 1;
+    }
+
+  /* We want to read in symbol extension records only once.  To do this
+     we need to read in the local symbols in parallel and save them for
+     later use; so hold pointers to the local symbols in an array.  */
+  amt = sizeof (Elf_Internal_Sym *) * bfd_count;
+  all_local_syms = (Elf_Internal_Sym **) bfd_zmalloc (amt);
+  if (all_local_syms == NULL)
+    return FALSE;
+
+  /* Walk over all the input BFDs, swapping in local symbols.  */
+  for (input_bfd = info->input_bfds, bfd_indx = 0;
+       input_bfd != NULL;
+       input_bfd = input_bfd->link_next, bfd_indx++)
+    {
+      Elf_Internal_Shdr *symtab_hdr;
+      Elf_Internal_Shdr *shndx_hdr;
+      Elf_Internal_Sym *isym;
+      Elf32_External_Sym *extsyms, *esym, *end_sy;
+      Elf_External_Sym_Shndx *shndx_buf, *shndx;
+      bfd_size_type sec_size;
+
+      /* We'll need the symbol table in a second.  */
+      symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+      if (symtab_hdr->sh_info == 0)
+	continue;
+
+      /* We need an array of the local symbols attached to the input bfd.
+	 Unfortunately, we're going to have to read & swap them in.  */
+      sec_size = symtab_hdr->sh_info;
+      sec_size *= sizeof (Elf_Internal_Sym);
+      local_syms = (Elf_Internal_Sym *) bfd_malloc (sec_size);
+      if (local_syms == NULL)
+	goto error_ret_free_local;
+
+      all_local_syms[bfd_indx] = local_syms;
+      sec_size = symtab_hdr->sh_info;
+      sec_size *= sizeof (Elf32_External_Sym);
+
+      /* Get the cached copy.  */
+      if (symtab_hdr->contents != NULL)
+        extsyms = (Elf32_External_Sym *) symtab_hdr->contents;
+      else
+        {
+          /* Go get them off disk.  */
+          bfd_size_type amt = symtab_hdr->sh_size;
+          extsyms = (Elf32_External_Sym *) bfd_malloc (amt);
+          if (extsyms == NULL)
+            goto error_ret_free_local;
+
+          if (bfd_seek (input_bfd, symtab_hdr->sh_offset, SEEK_SET) != 0
+              || bfd_bread ((PTR) extsyms, amt, input_bfd) != amt)
+            {
+            error_ret_free_ext_syms:
+              free (extsyms);
+              goto error_ret_free_local;
+            }
+        }
+      shndx_buf = NULL;
+      shndx_hdr = &elf_tdata (input_bfd)->symtab_shndx_hdr;
+      if (shndx_hdr->sh_size != 0)
+        {
+          bfd_size_type amt;
+
+          amt = symtab_hdr->sh_info * sizeof (Elf_External_Sym_Shndx);
+          shndx_buf = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
+          if (shndx_buf == NULL)
+            goto error_ret_free_ext_syms;
+          if (bfd_seek (input_bfd, shndx_hdr->sh_offset, SEEK_SET) != 0
+              || bfd_bread ((PTR) shndx_buf, amt, input_bfd) != amt)
+            {
+              free (shndx_buf);
+              goto error_ret_free_ext_syms;
+            }
+          shndx_hdr->contents = (PTR) shndx_buf;
+        }
+
+      /* Swap the local symbols in.  */
+      for (esym = extsyms, end_sy = esym + symtab_hdr->sh_info,
+	     isym = local_syms, shndx = shndx_buf;
+	   esym < end_sy;
+	   esym++, isym++, shndx = (shndx ? shndx + 1 : NULL))
+	bfd_elf32_swap_symbol_in (input_bfd, esym, shndx, isym);
+
+      /* Now we can free the external symbols.  */
+      free (shndx_buf);
+    }
+
+  for (input_bfd = info->input_bfds, bfd_indx = 0;
+       input_bfd != NULL;
+       input_bfd = input_bfd->link_next, bfd_indx++)
+    {
+      Elf_Internal_Shdr *symtab_hdr;
+      Elf_Internal_Sym *local_syms;
+      struct elf_link_hash_entry ** sym_hashes;
+
+      sym_hashes = elf_sym_hashes (input_bfd);
+
+      /* We'll need the symbol table in a second.  */
+      symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+      if (symtab_hdr->sh_info == 0)
+        continue;
+
+      local_syms = all_local_syms[bfd_indx];
+
+      /* Walk over each section attached to the input bfd.  */
+      for (section = input_bfd->sections;
+           section != NULL;
+           section = section->next)
+        {
+          Elf_Internal_Rela *internal_relocs, *irelaend, *irela;
+
+          /* If there aren't any relocs, then there's nothing more
+             to do.  */
+          if ((section->flags & SEC_RELOC) == 0
+              || section->reloc_count == 0)
+            continue;
+
+          /* If this section is a link-once section that will be
+             discarded, then don't create any stubs.  */
+          if (section->output_section == NULL
+              || section->output_section->owner != output_bfd)
+            continue;
+
+          /* Get the relocs.  */
+          internal_relocs
+            = _bfd_elf32_link_read_relocs (input_bfd, section, NULL,
+                                           (Elf_Internal_Rela *) NULL,
+                                           info->keep_memory);
+          if (internal_relocs == NULL)
+            goto error_ret_free_local;
+
+          /* Now examine each relocation.  */
+          irela = internal_relocs;
+          irelaend = irela + section->reloc_count;
+          for (; irela < irelaend; irela++)
+            {
+              unsigned int r_type, r_indx;
+              struct elf32_m68hc11_stub_hash_entry *stub_entry;
+              asection *sym_sec;
+              bfd_vma sym_value;
+              struct elf_link_hash_entry *hash;
+              const char *stub_name;
+              Elf_Internal_Sym *sym;
+
+              r_type = ELF32_R_TYPE (irela->r_info);
+
+              /* Only look at 16-bit relocs.  */
+              if (r_type != (unsigned int) R_M68HC11_16)
+                continue;
+
+              /* Now determine the call target, its name, value,
+                 section.  */
+              r_indx = ELF32_R_SYM (irela->r_info);
+              if (r_indx < symtab_hdr->sh_info)
+                {
+                  /* It's a local symbol.  */
+                  Elf_Internal_Shdr *hdr;
+                  bfd_boolean is_far;
+
+                  sym = local_syms + r_indx;
+                  hdr = elf_elfsections (input_bfd)[sym->st_shndx];
+                  sym_sec = hdr->bfd_section;
+                  is_far = (sym && (sym->st_other & STO_M68HC12_FAR));
+                  if (!is_far)
+                    continue;
+                  stub_name = (bfd_elf_string_from_elf_section
+                               (input_bfd, symtab_hdr->sh_link,
+                                sym->st_name));
+                  sym_value = sym->st_value;
+                  hash = NULL;
+                }
+              else
+                {
+                  /* It's an external symbol.  */
+                  int e_indx;
+
+                  e_indx = r_indx - symtab_hdr->sh_info;
+                  hash = (struct elf_link_hash_entry *)
+                    (sym_hashes[e_indx]);
+
+                  while (hash->root.type == bfd_link_hash_indirect
+                         || hash->root.type == bfd_link_hash_warning)
+                    hash = ((struct elf_link_hash_entry *)
+                            hash->root.u.i.link);
+
+                  if (hash->root.type == bfd_link_hash_defined
+                      || hash->root.type == bfd_link_hash_defweak)
+                    {
+                      if (!(hash->other & STO_M68HC12_FAR))
+                        continue;
+                    }
+                  else if (hash->root.type == bfd_link_hash_undefweak)
+                    {
+                      continue;
+                    }
+                  else if (hash->root.type == bfd_link_hash_undefined)
+                    {
+                      continue;
+                    }
+                  else
+                    {
+                      bfd_set_error (bfd_error_bad_value);
+                      goto error_ret_free_internal;
+                    }
+                  sym_sec = hash->root.u.def.section;
+                  sym_value = hash->root.u.def.value;
+                  stub_name = hash->root.root.string;
+                }
+
+              if (!stub_name)
+                goto error_ret_free_internal;
+
+              stub_entry = m68hc12_stub_hash_lookup
+                (htab->stub_hash_table,
+                 stub_name,
+                 FALSE, FALSE);
+              if (stub_entry == NULL)
+                {
+                  if (add_stub_section == 0)
+                    continue;
+
+                  stub_entry = m68hc12_add_stub (stub_name, section, htab);
+                  if (stub_entry == NULL)
+                    {
+                    error_ret_free_internal:
+                      if (elf_section_data (section)->relocs == NULL)
+                        free (internal_relocs);
+                      goto error_ret_free_local;
+                    }
+                }
+
+              stub_entry->target_value = sym_value;
+              stub_entry->target_section = sym_sec;
+            }
+
+          /* We're done with the internal relocs, free them.  */
+          if (elf_section_data (section)->relocs == NULL)
+            free (internal_relocs);
+        }
+    }
+
+  if (add_stub_section)
+    {
+      /* OK, we've added some stubs.  Find out the new size of the
+         stub sections.  */
+      for (stub_sec = htab->stub_bfd->sections;
+           stub_sec != NULL;
+           stub_sec = stub_sec->next)
+        {
+          stub_sec->_raw_size = 0;
+          stub_sec->_cooked_size = 0;
+        }
+
+      bfd_hash_traverse (htab->stub_hash_table, htab->size_one_stub, htab);
+    }
+  free (htab->all_local_syms);
+  return TRUE;
+
+ error_ret_free_local:
+  free (htab->all_local_syms);
+  return FALSE;
+}
+
+/* Export the trampoline addresses in the symbol table.  */
+static bfd_boolean
+m68hc11_elf_export_one_stub (gen_entry, in_arg)
+     struct bfd_hash_entry *gen_entry;
+     PTR in_arg;
+{
+  struct bfd_link_info *info;
+  struct m68hc11_elf_link_hash_table *htab;
+  struct elf32_m68hc11_stub_hash_entry *stub_entry;
+  char* name;
+  bfd_boolean result;
+
+  info = (struct bfd_link_info *) in_arg;
+  htab = m68hc11_elf_hash_table (info);
+
+  /* Massage our args to the form they really have.  */
+  stub_entry = (struct elf32_m68hc11_stub_hash_entry *) gen_entry;
+
+  /* Generate the trampoline according to HC11 or HC12.  */
+  result = (* htab->build_one_stub) (gen_entry, in_arg);
+
+  /* Make a printable name that does not conflict with the real function.  */
+  name = alloca (strlen (stub_entry->root.string) + 16);
+  sprintf (name, "tramp.%s", stub_entry->root.string);
+
+  /* Export the symbol for debugging/disassembling.  */
+  m68hc11_elf_set_symbol (htab->stub_bfd, info, name,
+                          stub_entry->stub_offset,
+                          stub_entry->stub_sec);
+  return result;
+}
+
+/* Export a symbol or set its value and section.  */
+static void
+m68hc11_elf_set_symbol (abfd, info, name, value, sec)
+     bfd* abfd;
+     struct bfd_link_info *info;
+     const char* name;
+     bfd_vma value;
+     asection* sec;
+{
+  struct elf_link_hash_entry *h;
+
+  h = (struct elf_link_hash_entry *)
+    bfd_link_hash_lookup (info->hash, name, FALSE, FALSE, FALSE);
+  if (h == NULL)
+    {
+      _bfd_generic_link_add_one_symbol (info, abfd,
+                                        name,
+                                        BSF_GLOBAL,
+                                        sec,
+                                        value,
+                                        (const char*) NULL,
+                                        TRUE, FALSE, NULL);
+    }
+  else
+    {
+      h->root.type = bfd_link_hash_defined;
+      h->root.u.def.value = value;
+      h->root.u.def.section = sec;
+    }
+}
+
+
+/* Build all the stubs associated with the current output file.  The
+   stubs are kept in a hash table attached to the main linker hash
+   table.  This function is called via m68hc12elf_finish in the
+   linker.  */
+
+bfd_boolean
+elf32_m68hc11_build_stubs (abfd, info)
+     bfd* abfd;
+     struct bfd_link_info *info;
+{
+  asection *stub_sec;
+  struct bfd_hash_table *table;
+  struct m68hc11_elf_link_hash_table *htab;
+  struct m68hc11_scan_param param;
+
+  m68hc11_elf_get_bank_parameters (info);
+  htab = m68hc11_elf_hash_table (info);
+
+  for (stub_sec = htab->stub_bfd->sections;
+       stub_sec != NULL;
+       stub_sec = stub_sec->next)
+    {
+      bfd_size_type size;
+
+      /* Allocate memory to hold the linker stubs.  */
+      size = stub_sec->_raw_size;
+      stub_sec->contents = (unsigned char *) bfd_zalloc (htab->stub_bfd, size);
+      if (stub_sec->contents == NULL && size != 0)
+	return FALSE;
+      stub_sec->_raw_size = 0;
+    }
+
+  /* Build the stubs as directed by the stub hash table.  */
+  table = htab->stub_hash_table;
+  bfd_hash_traverse (table, m68hc11_elf_export_one_stub, info);
+  
+  /* Scan the output sections to see if we use the memory banks.
+     If so, export the symbols that define how the memory banks
+     are mapped.  This is used by gdb and the simulator to obtain
+     the information.  It can be used by programs to burn the eprom
+     at the good addresses.  */
+  param.use_memory_banks = FALSE;
+  param.pinfo = &htab->pinfo;
+  bfd_map_over_sections (abfd, scan_sections_for_abi, &param);
+  if (param.use_memory_banks)
+    {
+      m68hc11_elf_set_symbol (abfd, info, BFD_M68HC11_BANK_START_NAME,
+                              htab->pinfo.bank_physical,
+                              bfd_abs_section_ptr);
+      m68hc11_elf_set_symbol (abfd, info, BFD_M68HC11_BANK_VIRTUAL_NAME,
+                              htab->pinfo.bank_virtual,
+                              bfd_abs_section_ptr);
+      m68hc11_elf_set_symbol (abfd, info, BFD_M68HC11_BANK_SIZE_NAME,
+                              htab->pinfo.bank_size,
+                              bfd_abs_section_ptr);
+    }
+
+  return TRUE;
+}
+
+void
+m68hc11_elf_get_bank_parameters (info)
+     struct bfd_link_info *info;
+{
+  unsigned i;
+  struct m68hc11_page_info *pinfo;
+  struct bfd_link_hash_entry *h;
+
+  pinfo = &m68hc11_elf_hash_table (info)->pinfo;
+  if (pinfo->bank_param_initialized)
+    return;
+
+  pinfo->bank_virtual = M68HC12_BANK_VIRT;
+  pinfo->bank_mask = M68HC12_BANK_MASK;
+  pinfo->bank_physical = M68HC12_BANK_BASE;
+  pinfo->bank_shift = M68HC12_BANK_SHIFT;
+  pinfo->bank_size = 1 << M68HC12_BANK_SHIFT;
+
+  h = bfd_link_hash_lookup (info->hash, BFD_M68HC11_BANK_START_NAME,
+                            FALSE, FALSE, TRUE);
+  if (h != (struct bfd_link_hash_entry*) NULL
+      && h->type == bfd_link_hash_defined)
+    pinfo->bank_physical = (h->u.def.value
+                            + h->u.def.section->output_section->vma
+                            + h->u.def.section->output_offset);
+
+  h = bfd_link_hash_lookup (info->hash, BFD_M68HC11_BANK_VIRTUAL_NAME,
+                            FALSE, FALSE, TRUE);
+  if (h != (struct bfd_link_hash_entry*) NULL
+      && h->type == bfd_link_hash_defined)
+    pinfo->bank_virtual = (h->u.def.value
+                           + h->u.def.section->output_section->vma
+                           + h->u.def.section->output_offset);
+
+  h = bfd_link_hash_lookup (info->hash, BFD_M68HC11_BANK_SIZE_NAME,
+                            FALSE, FALSE, TRUE);
+  if (h != (struct bfd_link_hash_entry*) NULL
+      && h->type == bfd_link_hash_defined)
+    pinfo->bank_size = (h->u.def.value
+                        + h->u.def.section->output_section->vma
+                        + h->u.def.section->output_offset);
+
+  pinfo->bank_shift = 0;
+  for (i = pinfo->bank_size; i != 0; i >>= 1)
+    pinfo->bank_shift++;
+  pinfo->bank_shift--;
+  pinfo->bank_mask = (1 << pinfo->bank_shift) - 1;
+  pinfo->bank_physical_end = pinfo->bank_physical + pinfo->bank_size;
+  pinfo->bank_param_initialized = 1;
+
+  h = bfd_link_hash_lookup (info->hash, "__far_trampoline", FALSE,
+                            FALSE, TRUE);
+  if (h != (struct bfd_link_hash_entry*) NULL
+      && h->type == bfd_link_hash_defined)
+    pinfo->trampoline_addr = (h->u.def.value
+                              + h->u.def.section->output_section->vma
+                              + h->u.def.section->output_offset);
+}
+
+/* Return 1 if the address is in banked memory.
+   This can be applied to a virtual address and to a physical address.  */
+int
+m68hc11_addr_is_banked (pinfo, addr)
+     struct m68hc11_page_info *pinfo;
+     bfd_vma addr;
+{
+  if (addr >= pinfo->bank_virtual)
+    return 1;
+
+  if (addr >= pinfo->bank_physical && addr <= pinfo->bank_physical_end)
+    return 1;
+
+  return 0;
+}
+
+/* Return the physical address seen by the processor, taking
+   into account banked memory.  */
+bfd_vma
+m68hc11_phys_addr (pinfo, addr)
+     struct m68hc11_page_info *pinfo;
+     bfd_vma addr;
+{
+  if (addr < pinfo->bank_virtual)
+    return addr;
+
+  /* Map the address to the memory bank.  */
+  addr -= pinfo->bank_virtual;
+  addr &= pinfo->bank_mask;
+  addr += pinfo->bank_physical;
+  return addr;
+}
+
+/* Return the page number corresponding to an address in banked memory.  */
+bfd_vma
+m68hc11_phys_page (pinfo, addr)
+     struct m68hc11_page_info *pinfo;
+     bfd_vma addr;
+{
+  if (addr < pinfo->bank_virtual)
+    return 0;
+
+  /* Map the address to the memory bank.  */
+  addr -= pinfo->bank_virtual;
+  addr >>= pinfo->bank_shift;
+  addr &= 0x0ff;
+  return addr;
+}
+
+/* This function is used for relocs which are only used for relaxing,
+   which the linker should otherwise ignore.  */
+
+bfd_reloc_status_type
+m68hc11_elf_ignore_reloc (abfd, reloc_entry, symbol, data, input_section,
+                          output_bfd, error_message)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     arelent *reloc_entry;
+     asymbol *symbol ATTRIBUTE_UNUSED;
+     PTR data ATTRIBUTE_UNUSED;
+     asection *input_section;
+     bfd *output_bfd;
+     char **error_message ATTRIBUTE_UNUSED;
+{
+  if (output_bfd != NULL)
+    reloc_entry->address += input_section->output_offset;
+  return bfd_reloc_ok;
+}
+
+bfd_reloc_status_type
+m68hc11_elf_special_reloc (abfd, reloc_entry, symbol, data, input_section,
+                           output_bfd, error_message)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     arelent *reloc_entry;
+     asymbol *symbol;
+     PTR data ATTRIBUTE_UNUSED;
+     asection *input_section;
+     bfd *output_bfd;
+     char **error_message ATTRIBUTE_UNUSED;
+{
+  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)
+    return bfd_reloc_continue;
+
+  if (reloc_entry->address > input_section->_cooked_size)
+    return bfd_reloc_outofrange;
+
+  abort();
+}
+
+asection *
+elf32_m68hc11_gc_mark_hook (sec, info, rel, h, sym)
+     asection *sec;
+     struct bfd_link_info *info ATTRIBUTE_UNUSED;
+     Elf_Internal_Rela *rel;
+     struct elf_link_hash_entry *h;
+     Elf_Internal_Sym *sym;
+{
+  if (h != NULL)
+    {
+      switch (ELF32_R_TYPE (rel->r_info))
+	{
+	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
+    return bfd_section_from_elf_index (sec->owner, sym->st_shndx);
+
+  return NULL;
+}
+
+bfd_boolean
+elf32_m68hc11_gc_sweep_hook (abfd, info, sec, relocs)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     struct bfd_link_info *info ATTRIBUTE_UNUSED;
+     asection *sec ATTRIBUTE_UNUSED;
+     const Elf_Internal_Rela *relocs ATTRIBUTE_UNUSED;
+{
+  /* We don't use got and plt entries for 68hc11/68hc12.  */
+  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.  */
+
+bfd_boolean
+elf32_m68hc11_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;
+  struct elf_link_hash_entry ** 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_M68HC11_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_M68HC11_GNU_VTENTRY:
+          if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_addend))
+            return FALSE;
+          break;
+        }
+    }
+
+  return TRUE;
+}
+
+static bfd_boolean
+m68hc11_get_relocation_value (abfd, info, local_sections, local_syms,
+                              rel, name,
+                              relocation, is_far)
+     bfd *abfd;
+     struct bfd_link_info *info;
+     asection **local_sections;
+     Elf_Internal_Sym* local_syms;
+     Elf_Internal_Rela* rel;
+     const char** name;
+     bfd_vma* relocation;
+     bfd_boolean* is_far;
+{
+  Elf_Internal_Shdr *symtab_hdr;
+  struct elf_link_hash_entry **sym_hashes;
+  unsigned long r_symndx;
+  asection *sec;
+  struct elf_link_hash_entry *h;
+  Elf_Internal_Sym *sym;
+  const char* stub_name = 0;
+
+  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  sym_hashes = elf_sym_hashes (abfd);
+
+  r_symndx = ELF32_R_SYM (rel->r_info);
+
+  /* This is a final link.  */
+  h = NULL;
+  sym = NULL;
+  sec = NULL;
+  if (r_symndx < symtab_hdr->sh_info)
+    {
+      sym = local_syms + r_symndx;
+      sec = local_sections[r_symndx];
+      *relocation = (sec->output_section->vma
+                     + sec->output_offset
+                     + sym->st_value);
+      *is_far = (sym && (sym->st_other & STO_M68HC12_FAR));
+      if (*is_far)
+        stub_name = (bfd_elf_string_from_elf_section
+                     (abfd, symtab_hdr->sh_link,
+                      sym->st_name));
+    }
+  else
+    {
+      h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+      while (h->root.type == bfd_link_hash_indirect
+             || h->root.type == bfd_link_hash_warning)
+        h = (struct elf_link_hash_entry *) h->root.u.i.link;
+      if (h->root.type == bfd_link_hash_defined
+          || h->root.type == bfd_link_hash_defweak)
+        {
+          sec = h->root.u.def.section;
+          *relocation = (h->root.u.def.value
+                         + sec->output_section->vma
+                         + sec->output_offset);
+        }
+      else if (h->root.type == bfd_link_hash_undefweak)
+        *relocation = 0;
+      else
+        {
+          if (!((*info->callbacks->undefined_symbol)
+                (info, h->root.root.string, abfd,
+                 sec, rel->r_offset, TRUE)))
+            return FALSE;
+          *relocation = 0;
+        }
+      *is_far = (h && (h->other & STO_M68HC12_FAR));
+      stub_name = h->root.root.string;
+    }
+
+  if (h != NULL)
+    *name = h->root.root.string;
+  else
+    {
+      *name = (bfd_elf_string_from_elf_section
+               (abfd, symtab_hdr->sh_link, sym->st_name));
+      if (*name == NULL || **name == '\0')
+        *name = bfd_section_name (input_bfd, sec);
+    }
+
+  if (*is_far && ELF32_R_TYPE (rel->r_info) == R_M68HC11_16)
+    {
+      struct elf32_m68hc11_stub_hash_entry* stub;
+      struct m68hc11_elf_link_hash_table *htab;
+
+      htab = m68hc11_elf_hash_table (info);
+      stub = m68hc12_stub_hash_lookup (htab->stub_hash_table,
+                                       *name, FALSE, FALSE);
+      if (stub)
+        {
+          *relocation = stub->stub_offset
+            + stub->stub_sec->output_section->vma
+            + stub->stub_sec->output_offset;
+          *is_far = FALSE;
+        }
+    }
+  return TRUE;
+}
+
+/* Relocate a 68hc11/68hc12 ELF section.  */
+bfd_boolean
+elf32_m68hc11_relocate_section (output_bfd, info, input_bfd, input_section,
+                                contents, relocs, local_syms, local_sections)
+     bfd *output_bfd ATTRIBUTE_UNUSED;
+     struct bfd_link_info *info;
+     bfd *input_bfd;
+     asection *input_section;
+     bfd_byte *contents;
+     Elf_Internal_Rela *relocs;
+     Elf_Internal_Sym *local_syms;
+     asection **local_sections;
+{
+  Elf_Internal_Shdr *symtab_hdr;
+  struct elf_link_hash_entry **sym_hashes;
+  Elf_Internal_Rela *rel, *relend;
+  const char *name;
+  struct m68hc11_page_info *pinfo;
+  struct elf_backend_data * const ebd = get_elf_backend_data (input_bfd);
+
+  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+  sym_hashes = elf_sym_hashes (input_bfd);
+
+  /* Get memory bank parameters.  */
+  m68hc11_elf_get_bank_parameters (info);
+  pinfo = &m68hc11_elf_hash_table (info)->pinfo;
+
+  rel = relocs;
+  relend = relocs + input_section->reloc_count;
+  for (; rel < relend; rel++)
+    {
+      int r_type;
+      arelent arel;
+      reloc_howto_type *howto;
+      unsigned long r_symndx;
+      Elf_Internal_Sym *sym;
+      asection *sec;
+      bfd_vma relocation;
+      bfd_reloc_status_type r = bfd_reloc_undefined;
+      bfd_vma phys_page;
+      bfd_vma phys_addr;
+      bfd_vma insn_addr;
+      bfd_vma insn_page;
+      bfd_boolean is_far;
+
+      r_symndx = ELF32_R_SYM (rel->r_info);
+      r_type = ELF32_R_TYPE (rel->r_info);
+
+      if (r_type == R_M68HC11_GNU_VTENTRY
+          || r_type == R_M68HC11_GNU_VTINHERIT )
+        continue;
+
+      if (info->relocateable)
+	{
+	  /* This is a relocateable link.  We don't have to change
+	     anything, unless the reloc is against a section symbol,
+	     in which case we have to adjust according to where the
+	     section symbol winds up in the output section.  */
+	  if (r_symndx < symtab_hdr->sh_info)
+	    {
+	      sym = local_syms + r_symndx;
+	      if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
+		{
+		  sec = local_sections[r_symndx];
+		  rel->r_addend += sec->output_offset + sym->st_value;
+		}
+	    }
+
+	  continue;
+	}
+      (*ebd->elf_info_to_howto_rel) (input_bfd, &arel, rel);
+      howto = arel.howto;
+
+      m68hc11_get_relocation_value (input_bfd, info,
+                                    local_sections, local_syms,
+                                    rel, &name, &relocation, &is_far);
+
+      /* Do the memory bank mapping.  */
+      phys_addr = m68hc11_phys_addr (pinfo, relocation + rel->r_addend);
+      phys_page = m68hc11_phys_page (pinfo, relocation + rel->r_addend);
+      switch (r_type)
+        {
+        case R_M68HC11_24:
+          /* Reloc used by 68HC12 call instruction.  */
+          bfd_put_16 (input_bfd, phys_addr,
+                      (bfd_byte*) contents + rel->r_offset);
+          bfd_put_8 (input_bfd, phys_page,
+                     (bfd_byte*) contents + rel->r_offset + 2);
+          r = bfd_reloc_ok;
+          r_type = R_M68HC11_NONE;
+          break;
+
+        case R_M68HC11_NONE:
+          r = bfd_reloc_ok;
+          break;
+
+        case R_M68HC11_LO16:
+          /* Reloc generated by %addr(expr) gas to obtain the
+             address as mapped in the memory bank window.  */
+          relocation = phys_addr;
+          break;
+
+        case R_M68HC11_PAGE:
+          /* Reloc generated by %page(expr) gas to obtain the
+             page number associated with the address.  */
+          relocation = phys_page;
+          break;
+
+        case R_M68HC11_16:
+          /* Get virtual address of instruction having the relocation.  */
+          if (is_far)
+            {
+              const char* msg;
+              char* buf;
+              msg = _("Reference to the far symbol `%s' using a wrong "
+                      "relocation may result in incorrect execution");
+              buf = alloca (strlen (msg) + strlen (name) + 10);
+              sprintf (buf, msg, name);
+              
+              (* info->callbacks->warning)
+                (info, buf, name, input_bfd, NULL, rel->r_offset);
+            }
+
+          /* Get virtual address of instruction having the relocation.  */
+          insn_addr = input_section->output_section->vma
+            + input_section->output_offset
+            + rel->r_offset;
+
+          insn_page = m68hc11_phys_page (pinfo, insn_addr);
+
+          if (m68hc11_addr_is_banked (pinfo, relocation + rel->r_addend)
+              && m68hc11_addr_is_banked (pinfo, insn_addr)
+              && phys_page != insn_page)
+            {
+              const char* msg;
+              char* buf;
+
+              msg = _("banked address [%lx:%04lx] (%lx) is not in the same bank "
+                      "as current banked address [%lx:%04lx] (%lx)");
+
+              buf = alloca (strlen (msg) + 128);
+              sprintf (buf, msg, phys_page, phys_addr,
+                       (long) (relocation + rel->r_addend),
+                       insn_page, m68hc11_phys_addr (pinfo, insn_addr),
+                       (long) (insn_addr));
+              if (!((*info->callbacks->warning)
+                    (info, buf, name, input_bfd, input_section,
+                     rel->r_offset)))
+                return FALSE;
+              break;
+            }
+          if (phys_page != 0 && insn_page == 0)
+            {
+              const char* msg;
+              char* buf;
+
+              msg = _("reference to a banked address [%lx:%04lx] in the "
+                      "normal address space at %04lx");
+
+              buf = alloca (strlen (msg) + 128);
+              sprintf (buf, msg, phys_page, phys_addr, insn_addr);
+              if (!((*info->callbacks->warning)
+                    (info, buf, name, input_bfd, input_section,
+                     insn_addr)))
+                return FALSE;
+
+              relocation = phys_addr;
+              break;
+            }
+
+          /* If this is a banked address use the phys_addr so that
+             we stay in the banked window.  */
+          if (m68hc11_addr_is_banked (pinfo, relocation + rel->r_addend))
+            relocation = phys_addr;
+          break;
+        }
+      if (r_type != R_M68HC11_NONE)
+        r = _bfd_final_link_relocate (howto, input_bfd, input_section,
+                                      contents, rel->r_offset,
+                                      relocation, rel->r_addend);
+
+      if (r != bfd_reloc_ok)
+	{
+	  const char * msg = (const char *) 0;
+
+	  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;
+	      break;
+
+	    case bfd_reloc_undefined:
+	      if (!((*info->callbacks->undefined_symbol)
+		    (info, name, input_bfd, input_section,
+		     rel->r_offset, TRUE)))
+		return FALSE;
+	      break;
+
+	    case bfd_reloc_outofrange:
+	      msg = _ ("internal error: out of range error");
+	      goto common_error;
+
+	    case bfd_reloc_notsupported:
+	      msg = _ ("internal error: unsupported relocation error");
+	      goto common_error;
+
+	    case bfd_reloc_dangerous:
+	      msg = _ ("internal error: dangerous error");
+	      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;
+	    }
+	}
+    }
+
+  return TRUE;
+}
+
+
+
+/* Set and control ELF flags in ELF header.  */
+
+bfd_boolean
+_bfd_m68hc11_elf_set_private_flags (abfd, flags)
+     bfd *abfd;
+     flagword flags;
+{
+  BFD_ASSERT (!elf_flags_init (abfd)
+	      || elf_elfheader (abfd)->e_flags == flags);
+
+  elf_elfheader (abfd)->e_flags = flags;
+  elf_flags_init (abfd) = TRUE;
+  return TRUE;
+}
+
+/* Merge backend specific data from an object file to the output
+   object file when linking.  */
+
+bfd_boolean
+_bfd_m68hc11_elf_merge_private_bfd_data (ibfd, obfd)
+     bfd *ibfd;
+     bfd *obfd;
+{
+  flagword old_flags;
+  flagword new_flags;
+  bfd_boolean ok = TRUE;
+
+  /* Check if we have the same endianess */
+  if (!_bfd_generic_verify_endian_match (ibfd, obfd))
+    return FALSE;
+
+  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;
+  elf_elfheader (obfd)->e_flags |= new_flags & EF_M68HC11_ABI;
+  old_flags = elf_elfheader (obfd)->e_flags;
+
+  if (! elf_flags_init (obfd))
+    {
+      elf_flags_init (obfd) = TRUE;
+      elf_elfheader (obfd)->e_flags = new_flags;
+      elf_elfheader (obfd)->e_ident[EI_CLASS]
+	= elf_elfheader (ibfd)->e_ident[EI_CLASS];
+
+      if (bfd_get_arch (obfd) == bfd_get_arch (ibfd)
+	  && bfd_get_arch_info (obfd)->the_default)
+	{
+	  if (! bfd_set_arch_mach (obfd, bfd_get_arch (ibfd),
+				   bfd_get_mach (ibfd)))
+	    return FALSE;
+	}
+
+      return TRUE;
+    }
+
+  /* Check ABI compatibility.  */
+  if ((new_flags & E_M68HC11_I32) != (old_flags & E_M68HC11_I32))
+    {
+      (*_bfd_error_handler)
+	(_("%s: linking files compiled for 16-bit integers (-mshort) "
+           "and others for 32-bit integers"),
+	 bfd_archive_filename (ibfd));
+      ok = FALSE;
+    }
+  if ((new_flags & E_M68HC11_F64) != (old_flags & E_M68HC11_F64))
+    {
+      (*_bfd_error_handler)
+	(_("%s: linking files compiled for 32-bit double (-fshort-double) "
+           "and others for 64-bit double"),
+	 bfd_archive_filename (ibfd));
+      ok = FALSE;
+    }
+  new_flags &= ~EF_M68HC11_ABI;
+  old_flags &= ~EF_M68HC11_ABI;
+
+  /* Warn about any other mismatches */
+  if (new_flags != old_flags)
+    {
+      (*_bfd_error_handler)
+	(_("%s: uses different e_flags (0x%lx) fields than previous modules (0x%lx)"),
+	 bfd_archive_filename (ibfd), (unsigned long) new_flags,
+	 (unsigned long) old_flags);
+      ok = FALSE;
+    }
+
+  if (! ok)
+    {
+      bfd_set_error (bfd_error_bad_value);
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+bfd_boolean
+_bfd_m68hc11_elf_print_private_bfd_data (abfd, ptr)
+     bfd *abfd;
+     PTR ptr;
+{
+  FILE *file = (FILE *) ptr;
+
+  BFD_ASSERT (abfd != NULL && ptr != NULL);
+
+  /* Print normal ELF private data.  */
+  _bfd_elf_print_private_bfd_data (abfd, ptr);
+
+  /* xgettext:c-format */
+  fprintf (file, _("private flags = %lx:"), elf_elfheader (abfd)->e_flags);
+
+  if (elf_elfheader (abfd)->e_flags & E_M68HC11_I32)
+    fprintf (file, _("[abi=32-bit int, "));
+  else
+    fprintf (file, _("[abi=16-bit int, "));
+
+  if (elf_elfheader (abfd)->e_flags & E_M68HC11_F64)
+    fprintf (file, _("64-bit double, "));
+  else
+    fprintf (file, _("32-bit double, "));
+
+  if (strcmp (bfd_get_target (abfd), "elf32-m68hc11") == 0)
+    fprintf (file, _("cpu=HC11]"));
+  else if (elf_elfheader (abfd)->e_flags & EF_M68HCS12_MACH)
+    fprintf (file, _("cpu=HCS12]"));
+  else
+    fprintf (file, _("cpu=HC12]"));    
+
+  if (elf_elfheader (abfd)->e_flags & E_M68HC12_BANKS)
+    fprintf (file, _(" [memory=bank-model]"));
+  else
+    fprintf (file, _(" [memory=flat]"));
+
+  fputc ('\n', file);
+
+  return TRUE;
+}
+
+static void scan_sections_for_abi (abfd, asect, arg)
+     bfd* abfd ATTRIBUTE_UNUSED;
+     asection* asect;
+     PTR arg;
+{
+  struct m68hc11_scan_param* p = (struct m68hc11_scan_param*) arg;
+
+  if (asect->vma >= p->pinfo->bank_virtual)
+    p->use_memory_banks = TRUE;
+}
+  
+/* Tweak the OSABI field of the elf header.  */
+
+void
+elf32_m68hc11_post_process_headers (abfd, link_info)
+     bfd *abfd;
+     struct bfd_link_info *link_info;
+{
+  struct m68hc11_scan_param param;
+
+  if (link_info == 0)
+    return;
+
+  m68hc11_elf_get_bank_parameters (link_info);
+
+  param.use_memory_banks = FALSE;
+  param.pinfo = &m68hc11_elf_hash_table (link_info)->pinfo;
+  bfd_map_over_sections (abfd, scan_sections_for_abi, &param);
+  if (param.use_memory_banks)
+    {
+      Elf_Internal_Ehdr * i_ehdrp;
+
+      i_ehdrp = elf_elfheader (abfd);
+      i_ehdrp->e_flags |= E_M68HC12_BANKS;
+    }
+}
+
Index: elf32-m68hc1x.h
===================================================================
RCS file: elf32-m68hc1x.h
diff -N elf32-m68hc1x.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ elf32-m68hc1x.h	19 Apr 2003 08:54:55 -0000
@@ -0,0 +1,205 @@
+/* Motorola 68HC11/68HC12-specific support for 32-bit ELF
+   Copyright 2003 Free Software Foundation, Inc.
+   Contributed by Stephane Carrez (stcarrez at nerim dot fr)
+
+This file is part of BFD, the Binary File Descriptor library.
+
+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
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifndef _ELF32_M68HC1X_H
+#define _ELF32_M68HC1X_H
+
+#include "elf-bfd.h"
+#include "bfdlink.h"
+#include "elf/m68hc11.h"
+
+/* Name of symbols exported by HC11/HC12 linker when there is a memory
+   bank window.  */
+#define BFD_M68HC11_BANK_START_NAME   "__bank_start"
+#define BFD_M68HC11_BANK_SIZE_NAME    "__bank_size"
+#define BFD_M68HC11_BANK_VIRTUAL_NAME "__bank_virtual"
+
+/* Set and control ELF flags in ELF header.  */
+extern bfd_boolean _bfd_m68hc11_elf_merge_private_bfd_data PARAMS ((bfd*,bfd*));
+extern bfd_boolean _bfd_m68hc11_elf_set_private_flags PARAMS ((bfd*,flagword));
+extern bfd_boolean _bfd_m68hc11_elf_print_private_bfd_data PARAMS ((bfd*,PTR));
+
+/* This hash entry is used to record a trampoline that must be generated
+   to call a far function using a normal calling convention ('jsr').
+   The trampoline is used when a pointer to a far function is used.
+   It takes care of installing the proper memory bank as well as creating
+   the 'call/rtc' calling convention.  */
+struct elf32_m68hc11_stub_hash_entry {
+
+  /* Base hash table entry structure.  */
+  struct bfd_hash_entry root;
+
+  /* The stub section.  */
+  asection *stub_sec;
+
+  /* Offset within stub_sec of the beginning of this stub.  */
+  bfd_vma stub_offset;
+
+  /* Given the symbol's value and its section we can determine its final
+     value when building the stubs (so the stub knows where to jump.  */
+  bfd_vma target_value;
+  asection *target_section;
+};
+
+/* Placeholder for the parameters to compute memory page and physical address.
+   The following formulas are used:
+
+   sym > bank_virtual =>
+     %addr(sym) = (((sym - bank_virtual) & bank_mask) + bank_physical
+     %page(sym) = (((sym - bank_virtual) >> bank_shift) % 256
+
+   sym < bank_virtual =>
+     %addr(sym) = sym
+     %page(sym) = 0
+
+
+   These parameters are obtained from the symbol table by looking
+   at the following:
+
+   __bank_start         Symbol marking the start of memory bank window
+                        (bank_physical)
+   __bank_virtual       Logical address of symbols for which the transformation
+                        must be computed
+   __bank_page_size     Size in bytes of page size (this is *NOT* the memory
+                        bank window size and the window size is always
+                        less or equal to the page size)
+
+   For 68HC12, the window is at 0x8000 and the page size is 16K (full window).
+   For 68HC11 this is board specific (implemented by external hardware).
+
+*/
+struct m68hc11_page_info
+{
+  bfd_vma bank_virtual;
+  bfd_vma bank_physical;
+  bfd_vma bank_physical_end;
+  bfd_vma bank_mask;
+  bfd_vma bank_size;
+  int bank_shift;
+  int bank_param_initialized;
+  bfd_vma trampoline_addr;
+};
+
+struct m68hc11_elf_link_hash_table
+{
+  struct elf_link_hash_table root;
+  struct m68hc11_page_info pinfo;
+
+  /* The stub hash table.  */
+  struct bfd_hash_table* stub_hash_table;
+
+  /* Linker stub bfd.  */
+  bfd *stub_bfd;
+
+  asection* stub_section;
+  asection* tramp_section;
+
+  /* Linker call-backs.  */
+  asection * (*add_stub_section) PARAMS ((const char *, asection *));
+
+  /* Assorted information used by elf32_hppa_size_stubs.  */
+  unsigned int bfd_count;
+  int top_index;
+  asection **input_list;
+  Elf_Internal_Sym **all_local_syms;
+
+  /* Small local sym to section mapping cache.  */
+  struct sym_sec_cache sym_sec;
+
+  bfd_boolean (* size_one_stub) PARAMS((struct bfd_hash_entry*, PTR));
+  bfd_boolean (* build_one_stub) PARAMS((struct bfd_hash_entry*, PTR));
+};
+
+/* Get the Sparc64 ELF linker hash table from a link_info structure.  */
+
+#define m68hc11_elf_hash_table(p) \
+  ((struct m68hc11_elf_link_hash_table *) ((p)->hash))
+
+/* Create a 68HC11/68HC12 ELF linker hash table.  */
+
+extern struct m68hc11_elf_link_hash_table* m68hc11_elf_hash_table_create
+  PARAMS ((bfd*));
+extern void m68hc11_elf_bfd_link_hash_table_free
+  PARAMS ((struct bfd_link_hash_table*));
+
+extern void m68hc11_elf_get_bank_parameters
+  PARAMS ((struct bfd_link_info*));
+
+/* Return 1 if the address is in banked memory.
+   This can be applied to a virtual address and to a physical address.  */
+extern int m68hc11_addr_is_banked
+  PARAMS ((struct m68hc11_page_info*, bfd_vma));
+
+/* Return the physical address seen by the processor, taking
+   into account banked memory.  */
+extern bfd_vma m68hc11_phys_addr
+  PARAMS ((struct m68hc11_page_info*, bfd_vma));
+
+/* Return the page number corresponding to an address in banked memory.  */
+extern bfd_vma m68hc11_phys_page
+  PARAMS ((struct m68hc11_page_info*, bfd_vma));
+
+bfd_reloc_status_type m68hc11_elf_ignore_reloc
+  PARAMS ((bfd *abfd, arelent *reloc_entry,
+           asymbol *symbol, PTR data, asection *input_section,
+           bfd *output_bfd, char **error_message));
+bfd_reloc_status_type m68hc11_elf_special_reloc
+  PARAMS ((bfd *abfd, arelent *reloc_entry,
+           asymbol *symbol, PTR data, asection *input_section,
+           bfd *output_bfd, char **error_message));
+
+/* GC mark and sweep.  */
+asection *elf32_m68hc11_gc_mark_hook
+  PARAMS ((asection *sec, struct bfd_link_info *info,
+           Elf_Internal_Rela *rel, struct elf_link_hash_entry *h,
+           Elf_Internal_Sym *sym));
+bfd_boolean elf32_m68hc11_gc_sweep_hook
+  PARAMS ((bfd *abfd, struct bfd_link_info *info,
+           asection *sec, const Elf_Internal_Rela *relocs));
+bfd_boolean elf32_m68hc11_check_relocs
+  PARAMS ((bfd * abfd, struct bfd_link_info * info,
+           asection * sec, const Elf_Internal_Rela * relocs));
+bfd_boolean elf32_m68hc11_relocate_section
+  PARAMS ((bfd *output_bfd, struct bfd_link_info *info,
+           bfd *input_bfd, asection *input_section,
+           bfd_byte *contents, Elf_Internal_Rela *relocs,
+           Elf_Internal_Sym *local_syms, asection **local_sections));
+
+bfd_boolean elf32_m68hc11_add_symbol_hook
+  PARAMS ((bfd *abfd, struct bfd_link_info *info,
+           const Elf_Internal_Sym *sym, const char **namep,
+           flagword *flagsp, asection **secp,
+           bfd_vma *valp));
+
+/* Tweak the OSABI field of the elf header.  */
+
+extern void elf32_m68hc11_post_process_headers
+  PARAMS ((bfd*, struct bfd_link_info*));
+
+int elf32_m68hc11_setup_section_lists
+  PARAMS ((bfd *, struct bfd_link_info *));
+
+bfd_boolean elf32_m68hc11_size_stubs
+  PARAMS ((bfd *, bfd *, struct bfd_link_info *,
+	   asection * (*) PARAMS ((const char *, asection *))));
+
+bfd_boolean elf32_m68hc11_build_stubs
+  PARAMS ((bfd* abfd, struct bfd_link_info *));
+#endif

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]