* elf32-m68hc11.c (elf_m68hc11_howto_table): Add the new relocs;
authorStephane Carrez <stcarrez@nerim.fr>
Tue, 13 Aug 2002 20:43:01 +0000 (20:43 +0000)
committerStephane Carrez <stcarrez@nerim.fr>
Tue, 13 Aug 2002 20:43:01 +0000 (20:43 +0000)
fix masks for PC-rel relocs.
(m68hc11_elf_ignore_reloc): New function.

* elf32-m68hc12.c (m68hc12_elf_special_reloc): New to handle specific
68HC12 banked addressing relocs.
(m68hc12_phys_addr): New to compute physical address of banked memory.
(m68hc12_phys_page): Likewise for page.
(m68hc12_addr_is_banked): New to see if address is in banked area.
(elf_m68hc12_howto_table): Add new relocs and rename to xx12.

bfd/ChangeLog
bfd/elf32-m68hc11.c
bfd/elf32-m68hc12.c

index c62266b10a3094916b0cc6eca51425cfab215a6e..7eff5eeee1f9b7d61f4d6ddbd71fdf3828437e8d 100644 (file)
@@ -1,3 +1,16 @@
+2002-08-13  Stephane Carrez  <stcarrez@nerim.fr>
+
+       * elf32-m68hc11.c (elf_m68hc11_howto_table): Add the new relocs;
+       fix masks for PC-rel relocs.
+       (m68hc11_elf_ignore_reloc): New function.
+
+       * elf32-m68hc12.c (m68hc12_elf_special_reloc): New to handle specific
+       68HC12 banked addressing relocs.
+       (m68hc12_phys_addr): New to compute physical address of banked memory.
+       (m68hc12_phys_page): Likewise for page.
+       (m68hc12_addr_is_banked): New to see if address is in banked area.
+       (elf_m68hc12_howto_table): Add new relocs and rename to xx12.
+
 2002-08-13  Stephane Carrez  <stcarrez@nerim.fr>
 
        * reloc.c (BFD_RELOC_M68HC11_RL_JUMP, BFD_RELOC_M68HC11_RL_GROUP,
index ae69ae255f51c8e05f82a099ba3abdad3e32f5db..de747b331020e714d97d630c77692218e985174d 100644 (file)
@@ -1,6 +1,6 @@
 /* Motorola 68HC11-specific support for 32-bit ELF
-   Copyright 1999, 2000 Free Software Foundation, Inc.
-   Contributed by Stephane Carrez (stcarrez@worldnet.fr)
+   Copyright 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+   Contributed by Stephane Carrez (stcarrez@nerim.fr)
    (Heavily copied from the D10V port by Martin Hunt (hunt@cygnus.com))
 
 This file is part of BFD, the Binary File Descriptor library.
@@ -30,6 +30,11 @@ PARAMS ((bfd * abfd, bfd_reloc_code_real_type code));
 static void m68hc11_info_to_howto_rel
 PARAMS ((bfd *, arelent *, Elf32_Internal_Rel *));
 
+static 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));
+
 /* Use REL instead of RELA to save space */
 #define USE_REL
 
@@ -110,7 +115,7 @@ static reloc_howto_type elf_m68hc11_howto_table[] = {
         bfd_elf_generic_reloc, /* special_function */
         "R_M68HC11_PCREL_8",   /* name */
         false,                 /* partial_inplace */
-        0x0,                   /* src_mask */
+        0x00ff,                /* src_mask */
         0x00ff,                /* dst_mask */
         false),                /* pcrel_offset */
 
@@ -171,7 +176,7 @@ static reloc_howto_type elf_m68hc11_howto_table[] = {
         bfd_elf_generic_reloc, /* special_function */
         "R_M68HC11_PCREL_16",  /* name */
         false,                 /* partial_inplace */
-        0x0,                   /* src_mask */
+        0xffff,                /* src_mask */
         0xffff,                /* dst_mask */
         false),                /* pcrel_offset */
 
@@ -204,6 +209,46 @@ static reloc_howto_type elf_m68hc11_howto_table[] = {
         0,                     /* src_mask */
         0,                     /* dst_mask */
         false),                /* pcrel_offset */
+
+  EMPTY_HOWTO (11),
+  EMPTY_HOWTO (12),
+  EMPTY_HOWTO (13),
+  EMPTY_HOWTO (14),
+  EMPTY_HOWTO (15),
+  EMPTY_HOWTO (16),
+  EMPTY_HOWTO (17),
+  EMPTY_HOWTO (18),
+  EMPTY_HOWTO (19),
+  
+  /* Mark beginning of a jump instruction (any form).  */
+  HOWTO (R_M68HC11_RL_JUMP,    /* type */
+        0,                     /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        0,                     /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,        /* complain_on_overflow */
+        m68hc11_elf_ignore_reloc,      /* special_function */
+        "R_M68HC11_RL_JUMP",   /* name */
+        true,                  /* partial_inplace */
+        0,                     /* src_mask */
+        0,                     /* dst_mask */
+        true),                 /* pcrel_offset */
+
+  /* Mark beginning of Gcc relaxation group instruction.  */
+  HOWTO (R_M68HC11_RL_GROUP,   /* type */
+        0,                     /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        0,                     /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,        /* complain_on_overflow */
+        m68hc11_elf_ignore_reloc,      /* special_function */
+        "R_M68HC11_RL_GROUP",  /* name */
+        true,                  /* partial_inplace */
+        0,                     /* src_mask */
+        0,                     /* dst_mask */
+        true),                 /* pcrel_offset */
 };
 
 /* Map BFD reloc types to M68HC11 ELF reloc types.  */
@@ -225,9 +270,11 @@ static const struct m68hc11_reloc_map m68hc11_reloc_map[] = {
   {BFD_RELOC_32, R_M68HC11_32},
   {BFD_RELOC_M68HC11_3B, R_M68HC11_3B},
 
-  /* The following relocs are defined but they probably don't work yet.  */
   {BFD_RELOC_VTABLE_INHERIT, R_M68HC11_GNU_VTINHERIT},
   {BFD_RELOC_VTABLE_ENTRY, R_M68HC11_GNU_VTENTRY},
+
+  {BFD_RELOC_M68HC11_RL_JUMP, R_M68HC11_RL_JUMP},
+  {BFD_RELOC_M68HC11_RL_GROUP, R_M68HC11_RL_GROUP},
 };
 
 static reloc_howto_type *
@@ -248,6 +295,25 @@ bfd_elf32_bfd_reloc_type_lookup (abfd, code)
   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
index 8f6ca49211f26575e407302fb8bfb9013ba56ecb..a2bb760ce502ec53be3eefd17acb7926b66492ef 100644 (file)
@@ -1,6 +1,6 @@
 /* Motorola 68HC12-specific support for 32-bit ELF
-   Copyright 1999, 2000 Free Software Foundation, Inc.
-   Contributed by Stephane Carrez (stcarrez@worldnet.fr)
+   Copyright 1999, 2000, 2002 Free Software Foundation, Inc.
+   Contributed by Stephane Carrez (stcarrez@nerim.fr)
    (Heavily copied from the D10V port by Martin Hunt (hunt@cygnus.com))
 
 This file is part of BFD, the Binary File Descriptor library.
@@ -24,12 +24,23 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #include "libbfd.h"
 #include "elf-bfd.h"
 #include "elf/m68hc11.h"
+#include "opcode/m68hc11.h"
 
 static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup
 PARAMS ((bfd * abfd, bfd_reloc_code_real_type code));
 static void m68hc11_info_to_howto_rel
 PARAMS ((bfd *, arelent *, Elf32_Internal_Rel *));
 
+static 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));
+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));
+
 /* Use REL instead of RELA to save space */
 #define USE_REL
 
@@ -37,6 +48,68 @@ PARAMS ((bfd *, arelent *, Elf32_Internal_Rel *));
    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
+   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
+   bank switching in function calls/returns.
+
+   For GNU Binutils to work, we consider there is a physical memory
+   at 0..0x0ffff and a kind of virtual memory above that.  Symbols
+   in virtual memory have their addresses treated in a special way
+   when disassembling and when linking.
+
+   For the linker to work properly, we must always relocate the virtual
+   memory as if it is mapped at 0x8000.  When a 16-bit relocation is
+   made in the virtual memory, we check that it does not cross the
+   memory bank where it is used.  This would involve a page change
+   which would be wrong.  The 24-bit relocation is for that and it
+   treats the address as a physical address + page number.
+
+
+                                       Banked
+                                       Address Space
+                                        |               |       Page n
+                                       +---------------+ 0x1010000
+                                        |               |
+                                        | jsr _foo      |
+                                        | ..            |       Page 3
+                                        | _foo:         |
+                                       +---------------+ 0x100C000
+                                       |               |
+                                        | call _bar     |
+                                       | ..            |       Page 2
+                                       | _bar:         |
+                                       +---------------+ 0x1008000
+                               /------>|               |
+                               |       | call _foo     |       Page 1
+                               |       |               |
+                               |       +---------------+ 0x1004000
+      Physical                 |       |               |
+      Address Space            |       |               |       Page 0
+                               |       |               |
+    +-----------+ 0x00FFFF     |       +---------------+ 0x1000000
+    |          |               |
+    | call _foo        |               |
+    |          |               |
+    +-----------+ 0x00BFFF -+---/
+    |          |           |
+    |          |           |
+    |          | 16K       |
+    |          |           |
+    +-----------+ 0x008000 -+
+    |          |
+    |          |
+    =          =
+    |          |
+    |          |
+    +-----------+ 0000
+
+
+   The 'call _foo' must be relocated with page 3 and 16-bit address
+   mapped at 0x8000.  
+
    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.  */
@@ -46,9 +119,9 @@ static reloc_howto_type elf_m68hc11_howto_table[] = {
         32,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
-        complain_overflow_bitfield,    /* complain_on_overflow */
+        complain_overflow_dont,/* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
-        "R_M68HC11_NONE",      /* name */
+        "R_M68HC12_NONE",      /* name */
         false,                 /* partial_inplace */
         0,                     /* src_mask */
         0,                     /* dst_mask */
@@ -63,7 +136,7 @@ static reloc_howto_type elf_m68hc11_howto_table[] = {
         0,                     /* bitpos */
         complain_overflow_bitfield,    /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
-        "R_M68HC11_8",         /* name */
+        "R_M68HC12_8",         /* name */
         false,                 /* partial_inplace */
         0x00ff,                /* src_mask */
         0x00ff,                /* dst_mask */
@@ -78,7 +151,7 @@ static reloc_howto_type elf_m68hc11_howto_table[] = {
         0,                     /* bitpos */
         complain_overflow_bitfield,    /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
-        "R_M68HC11_HI8",       /* name */
+        "R_M68HC12_HI8",       /* name */
         false,                 /* partial_inplace */
         0x00ff,                /* src_mask */
         0x00ff,                /* dst_mask */
@@ -93,7 +166,7 @@ static reloc_howto_type elf_m68hc11_howto_table[] = {
         0,                     /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
-        "R_M68HC11_LO8",       /* name */
+        "R_M68HC12_LO8",       /* name */
         false,                 /* partial_inplace */
         0x00ff,                /* src_mask */
         0x00ff,                /* dst_mask */
@@ -108,9 +181,9 @@ static reloc_howto_type elf_m68hc11_howto_table[] = {
         0,                     /* bitpos */
         complain_overflow_bitfield,    /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
-        "R_M68HC11_PCREL_8",   /* name */
+        "R_M68HC12_PCREL_8",   /* name */
         false,                 /* partial_inplace */
-        0x0,                   /* src_mask */
+        0x00ff,                /* src_mask */
         0x00ff,                /* dst_mask */
         false),                /* pcrel_offset */
 
@@ -122,8 +195,8 @@ static reloc_howto_type elf_m68hc11_howto_table[] = {
         false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont /*bitfield */ , /* complain_on_overflow */
-        bfd_elf_generic_reloc, /* special_function */
-        "R_M68HC11_16",        /* name */
+        m68hc12_elf_special_reloc,     /* special_function */
+        "R_M68HC12_16",        /* name */
         false,                 /* partial_inplace */
         0xffff,                /* src_mask */
         0xffff,                /* dst_mask */
@@ -139,7 +212,7 @@ static reloc_howto_type elf_m68hc11_howto_table[] = {
         0,                     /* bitpos */
         complain_overflow_bitfield,    /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
-        "R_M68HC11_32",        /* name */
+        "R_M68HC12_32",        /* name */
         false,                 /* partial_inplace */
         0xffffffff,            /* src_mask */
         0xffffffff,            /* dst_mask */
@@ -154,7 +227,7 @@ static reloc_howto_type elf_m68hc11_howto_table[] = {
         0,                     /* bitpos */
         complain_overflow_bitfield,    /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
-        "R_M68HC11_4B",        /* name */
+        "R_M68HC12_4B",        /* name */
         false,                 /* partial_inplace */
         0x003,                 /* src_mask */
         0x003,                 /* dst_mask */
@@ -169,9 +242,9 @@ static reloc_howto_type elf_m68hc11_howto_table[] = {
         0,                     /* bitpos */
         complain_overflow_dont,        /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
-        "R_M68HC11_PCREL_16",  /* name */
+        "R_M68HC12_PCREL_16",  /* name */
         false,                 /* partial_inplace */
-        0x0,                   /* src_mask */
+        0xffff,                /* src_mask */
         0xffff,                /* dst_mask */
         false),                /* pcrel_offset */
 
@@ -204,6 +277,88 @@ static reloc_howto_type elf_m68hc11_howto_table[] = {
         0,                     /* src_mask */
         0,                     /* dst_mask */
         false),                /* pcrel_offset */
+
+  /* A 24 bit relocation */
+  HOWTO (R_M68HC11_24,         /* type */
+        0,                     /* rightshift */
+        1,                     /* 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 */
+        "R_M68HC12_24",        /* name */
+        false,                 /* partial_inplace */
+        0xffff,                /* src_mask */
+        0xffff,                /* dst_mask */
+        false),                /* pcrel_offset */
+  
+  /* A 16-bit low relocation */
+  HOWTO (R_M68HC11_LO16,        /* type */
+        0,                     /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,        /* complain_on_overflow */
+        m68hc12_elf_special_reloc,/* special_function */
+        "R_M68HC12_LO16",      /* name */
+        false,                 /* partial_inplace */
+        0xffff,                /* src_mask */
+        0xffff,                /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* A page relocation */
+  HOWTO (R_M68HC11_PAGE,        /* type */
+        0,                     /* rightshift */
+        0,                     /* size (0 = byte, 1 = short, 2 = long) */
+        8,                     /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,        /* complain_on_overflow */
+        m68hc12_elf_special_reloc,/* special_function */
+        "R_M68HC12_PAGE",      /* name */
+        false,                 /* partial_inplace */
+        0x00ff,                /* src_mask */
+        0x00ff,                /* dst_mask */
+        false),                /* pcrel_offset */
+
+  EMPTY_HOWTO (14),
+  EMPTY_HOWTO (15),
+  EMPTY_HOWTO (16),
+  EMPTY_HOWTO (17),
+  EMPTY_HOWTO (18),
+  EMPTY_HOWTO (19),
+  
+  /* Mark beginning of a jump instruction (any form).  */
+  HOWTO (R_M68HC11_RL_JUMP,    /* type */
+        0,                     /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        0,                     /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,        /* complain_on_overflow */
+        m68hc11_elf_ignore_reloc,      /* special_function */
+        "R_M68HC12_RL_JUMP",   /* name */
+        true,                  /* partial_inplace */
+        0,                     /* src_mask */
+        0,                     /* dst_mask */
+        true),                 /* pcrel_offset */
+
+  /* Mark beginning of Gcc relaxation group instruction.  */
+  HOWTO (R_M68HC11_RL_GROUP,   /* type */
+        0,                     /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        0,                     /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,        /* complain_on_overflow */
+        m68hc11_elf_ignore_reloc,      /* special_function */
+        "R_M68HC12_RL_GROUP",  /* name */
+        true,                  /* partial_inplace */
+        0,                     /* src_mask */
+        0,                     /* dst_mask */
+        true),                 /* pcrel_offset */
 };
 
 /* Map BFD reloc types to M68HC11 ELF reloc types.  */
@@ -225,9 +380,15 @@ static const struct m68hc11_reloc_map m68hc11_reloc_map[] = {
   {BFD_RELOC_32, R_M68HC11_32},
   {BFD_RELOC_M68HC11_3B, R_M68HC11_3B},
 
-  /* The following relocs are defined but they probably don't work yet.  */
   {BFD_RELOC_VTABLE_INHERIT, R_M68HC11_GNU_VTINHERIT},
   {BFD_RELOC_VTABLE_ENTRY, R_M68HC11_GNU_VTENTRY},
+
+  {BFD_RELOC_M68HC11_LO16, R_M68HC11_LO16},
+  {BFD_RELOC_M68HC11_PAGE, R_M68HC11_PAGE},
+  {BFD_RELOC_M68HC11_24, R_M68HC11_24},
+
+  {BFD_RELOC_M68HC11_RL_JUMP, R_M68HC11_RL_JUMP},
+  {BFD_RELOC_M68HC11_RL_GROUP, R_M68HC11_RL_GROUP},
 };
 
 static reloc_howto_type *
@@ -248,6 +409,158 @@ bfd_elf32_bfd_reloc_type_lookup (abfd, code)
   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