/* 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.
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
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 */
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 */
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. */
{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 *
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
/* 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.
#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
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. */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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. */
{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 *
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