summaryrefslogtreecommitdiffstats
path: root/binutils-2.25/bfd/elf32-m68hc1x.c
diff options
context:
space:
mode:
Diffstat (limited to 'binutils-2.25/bfd/elf32-m68hc1x.c')
-rw-r--r--binutils-2.25/bfd/elf32-m68hc1x.c1497
1 files changed, 1497 insertions, 0 deletions
diff --git a/binutils-2.25/bfd/elf32-m68hc1x.c b/binutils-2.25/bfd/elf32-m68hc1x.c
new file mode 100644
index 00000000..427e3cd2
--- /dev/null
+++ b/binutils-2.25/bfd/elf32-m68hc1x.c
@@ -0,0 +1,1497 @@
+/* Motorola 68HC11/HC12-specific support for 32-bit ELF
+ Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+ 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
+ Contributed by Stephane Carrez (stcarrez@nerim.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 3 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., 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+#include "sysdep.h"
+#include "alloca-conf.h"
+#include "bfd.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
+ (const char *stub_name,
+ asection *section,
+ struct m68hc11_elf_link_hash_table *htab);
+
+static struct bfd_hash_entry *stub_hash_newfunc
+ (struct bfd_hash_entry *, struct bfd_hash_table *, const char *);
+
+static void m68hc11_elf_set_symbol (bfd* abfd, struct bfd_link_info *info,
+ const char* name, bfd_vma value,
+ asection* sec);
+
+static bfd_boolean m68hc11_elf_export_one_stub
+ (struct bfd_hash_entry *gen_entry, void *in_arg);
+
+static void scan_sections_for_abi (bfd*, asection*, void *);
+
+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 (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_zmalloc (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,
+ sizeof (struct elf_link_hash_entry),
+ M68HC11_ELF_DATA))
+ {
+ free (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)
+ {
+ free (ret);
+ return NULL;
+ }
+ if (!bfd_hash_table_init (ret->stub_hash_table, stub_hash_newfunc,
+ sizeof (struct elf32_m68hc11_stub_hash_entry)))
+ return NULL;
+
+ return ret;
+}
+
+/* Free the derived linker hash table. */
+
+void
+m68hc11_elf_bfd_link_hash_table_free (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_elf_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 (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 (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) (_("%B: cannot create stub entry %s"),
+ 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 (bfd *abfd, struct bfd_link_info *info,
+ 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;
+}
+
+/* Merge non-visibility st_other attributes, STO_M68HC12_FAR and
+ STO_M68HC12_INTERRUPT. */
+
+void
+elf32_m68hc11_merge_symbol_attribute (struct elf_link_hash_entry *h,
+ const Elf_Internal_Sym *isym,
+ bfd_boolean definition,
+ bfd_boolean dynamic ATTRIBUTE_UNUSED)
+{
+ if (definition)
+ h->other = ((isym->st_other & ~ELF_ST_VISIBILITY (-1))
+ | ELF_ST_VISIBILITY (h->other));
+}
+
+/* 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 (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 == NULL)
+ return -1;
+
+ if (bfd_get_flavour (info->output_bfd) != 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
+ strip_excluded_output_sections 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 (bfd *output_bfd, bfd *stub_bfd,
+ struct bfd_link_info *info,
+ asection * (*add_stub_section) (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);
+
+ if (htab == NULL)
+ return FALSE;
+
+ /* 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;
+
+ /* 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. */
+ local_syms = (Elf_Internal_Sym *) symtab_hdr->contents;
+ if (local_syms == NULL)
+ {
+ local_syms = bfd_elf_get_elf_syms (input_bfd, symtab_hdr,
+ symtab_hdr->sh_info, 0,
+ NULL, NULL, NULL);
+ /* Cache them for elf_link_input_bfd. */
+ symtab_hdr->contents = (unsigned char *) local_syms;
+ }
+ if (local_syms == NULL)
+ {
+ free (all_local_syms);
+ return FALSE;
+ }
+
+ all_local_syms[bfd_indx] = local_syms;
+ }
+
+ 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;
+ 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_elf_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;
+ is_far = (sym && (sym->st_other & STO_M68HC12_FAR));
+ if (!is_far)
+ continue;
+
+ if (sym->st_shndx >= elf_numsections (input_bfd))
+ sym_sec = NULL;
+ else
+ {
+ hdr = elf_elfsections (input_bfd)[sym->st_shndx];
+ sym_sec = hdr->bfd_section;
+ }
+ 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
+ || hash->root.type == bfd_link_hash_new)
+ {
+ 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->size = 0;
+ }
+
+ bfd_hash_traverse (htab->stub_hash_table, htab->size_one_stub, htab);
+ }
+ free (all_local_syms);
+ return TRUE;
+
+ error_ret_free_local:
+ free (all_local_syms);
+ return FALSE;
+}
+
+/* Export the trampoline addresses in the symbol table. */
+static bfd_boolean
+m68hc11_elf_export_one_stub (struct bfd_hash_entry *gen_entry, void *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);
+ if (htab == NULL)
+ return FALSE;
+
+ /* 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 (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 (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);
+ if (htab == NULL)
+ return FALSE;
+
+ 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->size;
+ stub_sec->contents = (unsigned char *) bfd_zalloc (htab->stub_bfd, size);
+ if (stub_sec->contents == NULL && size != 0)
+ return FALSE;
+ stub_sec->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 (struct bfd_link_info *info)
+{
+ unsigned i;
+ struct m68hc11_page_info *pinfo;
+ struct bfd_link_hash_entry *h;
+ struct m68hc11_elf_link_hash_table *htab;
+
+ htab = m68hc11_elf_hash_table (info);
+ if (htab == NULL)
+ return;
+
+ pinfo = & htab->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 (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 (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 (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 (bfd *abfd ATTRIBUTE_UNUSED,
+ arelent *reloc_entry,
+ asymbol *symbol ATTRIBUTE_UNUSED,
+ void *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 (bfd *abfd ATTRIBUTE_UNUSED,
+ arelent *reloc_entry,
+ asymbol *symbol,
+ void *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 > bfd_get_section_limit (abfd, input_section))
+ return bfd_reloc_outofrange;
+
+ abort();
+}
+
+/* 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 (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;
+ const Elf_Internal_Rela * rel;
+ const Elf_Internal_Rela * rel_end;
+
+ if (info->relocatable)
+ return TRUE;
+
+ symtab_hdr = & elf_tdata (abfd)->symtab_hdr;
+ sym_hashes = elf_sym_hashes (abfd);
+ 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];
+ 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;
+
+ /* PR15323, ref flags aren't set for references in the same
+ object. */
+ h->root.non_ir_ref = 1;
+ }
+
+ 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_elf_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:
+ BFD_ASSERT (h != NULL);
+ if (h != NULL
+ && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
+ return FALSE;
+ break;
+ }
+ }
+
+ return TRUE;
+}
+
+/* Relocate a 68hc11/68hc12 ELF section. */
+bfd_boolean
+elf32_m68hc11_relocate_section (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 = NULL;
+ struct m68hc11_page_info *pinfo;
+ const struct elf_backend_data * const ebd = get_elf_backend_data (input_bfd);
+ struct m68hc11_elf_link_hash_table *htab;
+ unsigned long e_flags;
+
+ symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+ sym_hashes = elf_sym_hashes (input_bfd);
+ e_flags = elf_elfheader (input_bfd)->e_flags;
+
+ htab = m68hc11_elf_hash_table (info);
+ if (htab == NULL)
+ return FALSE;
+
+ /* Get memory bank parameters. */
+ m68hc11_elf_get_bank_parameters (info);
+
+ pinfo = & htab->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 = 0;
+ 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 = FALSE;
+ bfd_boolean is_xgate_symbol = FALSE;
+ bfd_boolean is_section_symbol = FALSE;
+ struct elf_link_hash_entry *h;
+ bfd_vma val;
+
+ 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;
+
+ (*ebd->elf_info_to_howto_rel) (input_bfd, &arel, rel);
+ howto = arel.howto;
+
+ 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));
+ is_xgate_symbol = (sym && (sym->st_target_internal));
+ is_section_symbol = ELF_ST_TYPE (sym->st_info) & STT_SECTION;
+ }
+ else
+ {
+ bfd_boolean unresolved_reloc, warned;
+
+ RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
+ r_symndx, symtab_hdr, sym_hashes,
+ h, sec, relocation, unresolved_reloc,
+ warned);
+
+ is_far = (h && (h->other & STO_M68HC12_FAR));
+ is_xgate_symbol = (h && (h->target_internal));
+ }
+
+ if (sec != NULL && discarded_section (sec))
+ RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
+ rel, 1, relend, howto, 0, contents);
+
+ if (info->relocatable)
+ {
+ /* This is a relocatable 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 (sym != NULL && ELF_ST_TYPE (sym->st_info) == STT_SECTION)
+ rel->r_addend += sec->output_offset;
+ continue;
+ }
+
+ 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);
+ }
+
+ if (is_far && ELF32_R_TYPE (rel->r_info) == R_M68HC11_16)
+ {
+ struct elf32_m68hc11_stub_hash_entry* stub;
+
+ 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;
+ }
+ }
+
+ /* 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_M68HC12_LO8XG:
+ /* This relocation is specific to XGATE IMM16 calls and will precede
+ a HI8. tc-m68hc11 only generates them in pairs.
+ Leave the relocation to the HI8XG step. */
+ r = bfd_reloc_ok;
+ r_type = R_M68HC11_NONE;
+ break;
+
+ case R_M68HC12_HI8XG:
+ /* This relocation is specific to XGATE IMM16 calls and must follow
+ a LO8XG. Does not actually check that it was a LO8XG.
+ Adjusts high and low bytes. */
+ relocation = phys_addr;
+ if ((e_flags & E_M68HC11_XGATE_RAMOFFSET)
+ && (relocation >= 0x2000))
+ relocation += 0xc000; /* HARDCODED RAM offset for XGATE. */
+
+ /* Fetch 16 bit value including low byte in previous insn. */
+ val = (bfd_get_8 (input_bfd, (bfd_byte*) contents + rel->r_offset) << 8)
+ | bfd_get_8 (input_bfd, (bfd_byte*) contents + rel->r_offset - 2);
+
+ /* Add on value to preserve carry, then write zero to high byte. */
+ relocation += val;
+
+ /* Write out top byte. */
+ bfd_put_8 (input_bfd, (relocation >> 8) & 0xff,
+ (bfd_byte*) contents + rel->r_offset);
+
+ /* Write out low byte to previous instruction. */
+ bfd_put_8 (input_bfd, relocation & 0xff,
+ (bfd_byte*) contents + rel->r_offset - 2);
+
+ /* Mark as relocation completed. */
+ r = bfd_reloc_ok;
+ r_type = R_M68HC11_NONE;
+ break;
+
+ /* The HI8 and LO8 relocs are generated by %hi(expr) %lo(expr)
+ assembler directives. %hi does not support carry. */
+ case R_M68HC11_HI8:
+ case R_M68HC11_LO8:
+ relocation = phys_addr;
+ break;
+
+ 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 we are linking an S12 instruction against an XGATE symbol, we
+ need to change the offset of the symbol value so that it's correct
+ from the S12's perspective. */
+ if (is_xgate_symbol)
+ {
+ /* The ram in the global space is mapped to 0x2000 in the 16-bit
+ address space for S12 and 0xE000 in the 16-bit address space
+ for XGATE. */
+ if (relocation >= 0xE000)
+ {
+ /* We offset the address by the difference
+ between these two mappings. */
+ relocation -= 0xC000;
+ break;
+ }
+ else
+ {
+ const char * msg;
+ char * buf;
+
+ msg = _("XGATE address (%lx) is not within shared RAM"
+ "(0xE000-0xFFFF), therefore you must manually offset "
+ "the address, and possibly manage the page, in your "
+ "code.");
+ buf = alloca (strlen (msg) + 128);
+ sprintf (buf, msg, phys_addr);
+ if (!((*info->callbacks->warning) (info, buf, name, input_bfd,
+ input_section, insn_addr)))
+ return FALSE;
+ break;
+ }
+ }
+
+ if (m68hc11_addr_is_banked (pinfo, relocation + rel->r_addend)
+ && m68hc11_addr_is_banked (pinfo, insn_addr)
+ && phys_page != insn_page && !(e_flags & E_M68HC11_NO_BANK_WARNING))
+ {
+ 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 we are linking an XGATE instruction against an S12 symbol, we
+ need to change the offset of the symbol value so that it's correct
+ from the XGATE's perspective. */
+ if (!strcmp (howto->name, "R_XGATE_IMM8_LO")
+ || !strcmp (howto->name, "R_XGATE_IMM8_HI"))
+ {
+ /* We can only offset S12 addresses that lie within the non-paged
+ area of RAM. */
+ if (!is_xgate_symbol && !is_section_symbol)
+ {
+ /* The ram in the global space is mapped to 0x2000 and stops at
+ 0x4000 in the 16-bit address space for S12 and 0xE000 in the
+ 16-bit address space for XGATE. */
+ if (relocation >= 0x2000 && relocation < 0x4000)
+ /* We offset the address by the difference
+ between these two mappings. */
+ relocation += 0xC000;
+ else
+ {
+ const char * msg;
+ char * buf;
+
+ /* Get virtual address of instruction having the relocation. */
+ insn_addr = input_section->output_section->vma
+ + input_section->output_offset + rel->r_offset;
+
+ msg = _("S12 address (%lx) is not within shared RAM"
+ "(0x2000-0x4000), therefore you must manually "
+ "offset the address in your code");
+ buf = alloca (strlen (msg) + 128);
+ sprintf (buf, msg, phys_addr);
+ if (!((*info->callbacks->warning) (info, buf, name, input_bfd,
+ input_section, insn_addr)))
+ return FALSE;
+ break;
+ }
+ }
+ }
+
+ if (r_type != R_M68HC11_NONE)
+ {
+ if ((r_type == R_M68HC12_PCREL_9) || (r_type == R_M68HC12_PCREL_10))
+ r = _bfd_final_link_relocate (howto, input_bfd, input_section,
+ contents, rel->r_offset,
+ relocation - 2, rel->r_addend);
+ else
+ 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, NULL, 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 (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 (bfd *ibfd, bfd *obfd)
+{
+ flagword old_flags;
+ flagword new_flags;
+ bfd_boolean ok = TRUE;
+
+ /* Check if we have the same endianness */
+ 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)
+ (_("%B: linking files compiled for 16-bit integers (-mshort) "
+ "and others for 32-bit integers"), ibfd);
+ ok = FALSE;
+ }
+ if ((new_flags & E_M68HC11_F64) != (old_flags & E_M68HC11_F64))
+ {
+ (*_bfd_error_handler)
+ (_("%B: linking files compiled for 32-bit double (-fshort-double) "
+ "and others for 64-bit double"), ibfd);
+ ok = FALSE;
+ }
+
+ /* Processor compatibility. */
+ if (!EF_M68HC11_CAN_MERGE_MACH (new_flags, old_flags))
+ {
+ (*_bfd_error_handler)
+ (_("%B: linking files compiled for HCS12 with "
+ "others compiled for HC12"), 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;
+
+ new_flags &= ~(EF_M68HC11_ABI | EF_M68HC11_MACH_MASK);
+ old_flags &= ~(EF_M68HC11_ABI | EF_M68HC11_MACH_MASK);
+
+ /* Warn about any other mismatches */
+ if (new_flags != old_flags)
+ {
+ (*_bfd_error_handler)
+ (_("%B: uses different e_flags (0x%lx) fields than previous modules (0x%lx)"),
+ 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 (bfd *abfd, void *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]"));
+
+ if (elf_elfheader (abfd)->e_flags & E_M68HC11_XGATE_RAMOFFSET)
+ fprintf (file, _(" [XGATE RAM offsetting]"));
+
+ fputc ('\n', file);
+
+ return TRUE;
+}
+
+static void scan_sections_for_abi (bfd *abfd ATTRIBUTE_UNUSED,
+ asection *asect, void *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 (bfd *abfd, struct bfd_link_info *link_info)
+{
+ struct m68hc11_scan_param param;
+ struct m68hc11_elf_link_hash_table *htab;
+
+ if (link_info == NULL)
+ return;
+
+ htab = m68hc11_elf_hash_table (link_info);
+ if (htab == NULL)
+ return;
+
+ m68hc11_elf_get_bank_parameters (link_info);
+
+ param.use_memory_banks = FALSE;
+ param.pinfo = & htab->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;
+ }
+}