summaryrefslogtreecommitdiff
path: root/bfd/elf32-xstormy16.c
diff options
context:
space:
mode:
authorGeoffrey Keating <geoffk@geoffk.org>2001-12-08 03:46:03 +0000
committerGeoffrey Keating <geoffk@geoffk.org>2001-12-08 03:46:03 +0000
commitdc32364075a4bf20d80cbea76743c51ba0b98482 (patch)
treecfd33b5dbbcb12189ab6932d8beff73288ec1ec7 /bfd/elf32-xstormy16.c
parent350e9bfdd7883d99e77c639a38a8ee85bcba76da (diff)
downloadbinutils-redhat-dc32364075a4bf20d80cbea76743c51ba0b98482.tar.gz
Index: bfd/ChangeLog
2001-12-07 Geoffrey Keating <geoffk@redhat.com> Richard Henderson <rth@redhat.com> Corinna Vinschen <vinschen@redhat.com> * Makefile.am: Add support for xstormy16. * archures.c: Add support for xstormy16. * config.bfd: Add support for xstormy16. * configure.in: Add support for xstormy16. * reloc.c: Add support for xstormy16. * targets.c: Add support for xstormy16. * cpu-xstormy16.c: New file. * elf32-xstormy16.c: New file. * Makefile.in: Regenerated. * bfd-in2.h: Regenerated. * configure: Regenerated. * libbfd.h: Regenerated. Index: binutils/ChangeLog 2001-12-07 Geoffrey Keating <geoffk@redhat.com> * readelf.c (guess_is_rela): Add support for stormy16. (dump_relocations): Likewise. (get_machine_name): Likewise. Index: gas/ChangeLog 2001-12-07 Geoffrey Keating <geoffk@redhat.com> Richard Henderson <rth@redhat.com> * configure.in: Add support for xstormy16. * configure: Regenerated. * Makefile.am: Add support for xstormy16. * Makefile.in: Regenerated. * config/tc-xstormy16.c: New file. * config/tc-xstormy16.h: New file. Index: gas/testsuite/ChangeLog 2001-12-07 Geoffrey Keating <geoffk@redhat.com> matthew green <mrg@redhat.com> * gas/xstormy16/allinsn.d: New file. * gas/xstormy16/allinsn.exp: New file. * gas/xstormy16/allinsn.s: New file. * gas/xstormy16/allinsn.sh: New file. * gas/xstormy16/gcc.d: New file. * gas/xstormy16/gcc.s: New file. * gas/xstormy16/gcc.sh: New file. * gas/xstormy16/reloc-1.d: New file. * gas/xstormy16/reloc-1.s: New file. * gas/xstormy16/reloc-2.d: New file. * gas/xstormy16/reloc-2.s: New file. Index: ld/ChangeLog 2001-12-07 Geoffrey Keating <geoffk@redhat.com> Richard Henderson <rth@redhat.com> * Makefile.am: Add support for xstormy16. * configure.tgt: Add support for xstormy16. * Makefile.in: Regenerate. * emulparams/elf32xstormy16.sh: New file. * scripttempl/xstormy16.sc: New file. Index: opcodes/ChangeLog 2001-12-07 Geoffrey Keating <geoffk@redhat.com> * Makefile.am: Add support for xstormy16. * Makefile.in: Regenerate. * configure.in: Add support for xstormy16. * configure: Regenerate. * disassemble.c: Add support for xstormy16. * xstormy16-asm.c: New generated file. * xstormy16-desc.c: New generated file. * xstormy16-desc.h: New generated file. * xstormy16-dis.c: New generated file. * xstormy16-ibld.c: New generated file. * xstormy16-opc.c: New generated file. * xstormy16-opc.h: New generated file. Index: include/ChangeLog 2001-12-07 Geoffrey Keating <geoffk@redhat.com> * dis-asm.h (print_insn_xstormy16): Declare. Index: include/elf/ChangeLog 2001-12-07 Geoffrey Keating <geoffk@redhat.com> Richard Henderson <rth@redhat.com> * common.h (EM_XSTORMY16): Define. * xstormy16.h: New file.
Diffstat (limited to 'bfd/elf32-xstormy16.c')
-rw-r--r--bfd/elf32-xstormy16.c1074
1 files changed, 1074 insertions, 0 deletions
diff --git a/bfd/elf32-xstormy16.c b/bfd/elf32-xstormy16.c
new file mode 100644
index 0000000000..5be799e957
--- /dev/null
+++ b/bfd/elf32-xstormy16.c
@@ -0,0 +1,1074 @@
+/* XSTORMY16-specific support for 32-bit ELF.
+ Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+
+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 "libbfd.h"
+#include "elf-bfd.h"
+#include "elf/xstormy16.h"
+
+/* Forward declarations. */
+static reloc_howto_type * xstormy16_reloc_type_lookup
+ PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
+static void xstormy16_info_to_howto_rela
+ PARAMS ((bfd *, arelent *, Elf32_Internal_Rela *));
+static bfd_reloc_status_type xstormy16_elf_24_reloc
+ PARAMS ((bfd *abfd, arelent *reloc_entry, asymbol *symbol,
+ PTR data, asection *input_section, bfd *output_bfd,
+ char **error_message));
+static boolean xstormy16_elf_check_relocs
+ PARAMS ((bfd *, struct bfd_link_info *, asection *,
+ const Elf_Internal_Rela *));
+static boolean xstormy16_relax_plt_check
+ PARAMS ((struct elf_link_hash_entry *, PTR));
+static boolean xstormy16_relax_plt_realloc
+ PARAMS ((struct elf_link_hash_entry *, PTR));
+static boolean xstormy16_elf_relax_section
+ PARAMS ((bfd *abfd, asection *sec, struct bfd_link_info *link_info,
+ boolean *again));
+static boolean xstormy16_elf_always_size_sections
+ PARAMS ((bfd *, struct bfd_link_info *));
+static boolean xstormy16_elf_relocate_section
+ PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
+ Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
+static boolean xstormy16_elf_finish_dynamic_sections
+ PARAMS((bfd *, struct bfd_link_info *));
+static boolean xstormy16_elf_gc_sweep_hook
+ PARAMS ((bfd *, struct bfd_link_info *, asection *,
+ const Elf_Internal_Rela *));
+static asection * xstormy16_elf_gc_mark_hook
+ PARAMS ((bfd *, struct bfd_link_info *, Elf_Internal_Rela *,
+ struct elf_link_hash_entry *, Elf_Internal_Sym *));
+
+static reloc_howto_type xstormy16_elf_howto_table [] =
+{
+ /* This reloc does nothing. */
+ HOWTO (R_XSTORMY16_NONE, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_XSTORMY16_NONE", /* name */
+ false, /* partial_inplace */
+ 0, /* src_mask */
+ 0, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* A 32 bit absolute relocation. */
+ HOWTO (R_XSTORMY16_32, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_XSTORMY16_32", /* name */
+ false, /* partial_inplace */
+ 0, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* A 16 bit absolute relocation. */
+ HOWTO (R_XSTORMY16_16, /* type */
+ 0, /* rightshift */
+ 1, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_XSTORMY16_16", /* name */
+ false, /* partial_inplace */
+ 0, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* An 8 bit absolute relocation. */
+ HOWTO (R_XSTORMY16_8, /* type */
+ 0, /* rightshift */
+ 0, /* size (0 = byte, 1 = short, 2 = long) */
+ 8, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_XSTORMY16_8", /* name */
+ false, /* partial_inplace */
+ 0, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* A 32 bit pc-relative relocation. */
+ HOWTO (R_XSTORMY16_PC32, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ true, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_XSTORMY16_PC32", /* name */
+ false, /* partial_inplace */
+ 0, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ true), /* pcrel_offset */
+
+ /* A 16 bit pc-relative relocation. */
+ HOWTO (R_XSTORMY16_PC16, /* type */
+ 0, /* rightshift */
+ 1, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ true, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_XSTORMY16_PC16", /* name */
+ false, /* partial_inplace */
+ 0, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ true), /* pcrel_offset */
+
+ /* An 8 bit pc-relative relocation. */
+ HOWTO (R_XSTORMY16_PC8, /* type */
+ 0, /* rightshift */
+ 0, /* size (0 = byte, 1 = short, 2 = long) */
+ 8, /* bitsize */
+ true, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_XSTORMY16_PC8", /* name */
+ false, /* partial_inplace */
+ 0, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ true), /* pcrel_offset */
+
+ /* A 12-bit pc-relative relocation suitable for the branch instructions. */
+ HOWTO (R_XSTORMY16_REL_12, /* type */
+ 1, /* rightshift */
+ 1, /* size (0 = byte, 1 = short, 2 = long) */
+ 11, /* bitsize */
+ true, /* pc_relative */
+ 1, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_XSTORMY16_REL_12", /* name */
+ true, /* partial_inplace */
+ 0, /* src_mask */
+ 0x0fff, /* dst_mask */
+ true), /* pcrel_offset */
+
+ /* A 24-bit absolute relocation suitable for the jump instructions. */
+ HOWTO (R_XSTORMY16_24, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 24, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_unsigned, /* complain_on_overflow */
+ xstormy16_elf_24_reloc, /* special_function */
+ "R_XSTORMY16_24", /* name */
+ true, /* partial_inplace */
+ 0, /* src_mask */
+ 0xffff00ff, /* dst_mask */
+ true), /* pcrel_offset */
+
+ /* A 16 bit absolute relocation to a function pointer. */
+ HOWTO (R_XSTORMY16_FPTR16, /* type */
+ 0, /* rightshift */
+ 1, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_XSTORMY16_FPTR16", /* name */
+ false, /* partial_inplace */
+ 0, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ false), /* pcrel_offset */
+};
+
+static reloc_howto_type xstormy16_elf_howto_table2 [] =
+{
+ /* GNU extension to record C++ vtable hierarchy */
+ HOWTO (R_XSTORMY16_GNU_VTINHERIT, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 0, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ NULL, /* special_function */
+ "R_XSTORMY16_GNU_VTINHERIT", /* name */
+ false, /* partial_inplace */
+ 0, /* src_mask */
+ 0, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* GNU extension to record C++ vtable member usage */
+ HOWTO (R_XSTORMY16_GNU_VTENTRY, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 0, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ _bfd_elf_rel_vtable_reloc_fn, /* special_function */
+ "R_XSTORMY16_GNU_VTENTRY", /* name */
+ false, /* partial_inplace */
+ 0, /* src_mask */
+ 0, /* dst_mask */
+ false), /* pcrel_offset */
+
+};
+
+/* Map BFD reloc types to XSTORMY16 ELF reloc types. */
+
+struct xstormy16_reloc_map
+{
+ bfd_reloc_code_real_type bfd_reloc_val;
+ unsigned int xstormy16_reloc_val;
+};
+
+static const struct xstormy16_reloc_map xstormy16_reloc_map [] =
+{
+ { BFD_RELOC_NONE, R_XSTORMY16_NONE },
+ { BFD_RELOC_32, R_XSTORMY16_32 },
+ { BFD_RELOC_16, R_XSTORMY16_16 },
+ { BFD_RELOC_8, R_XSTORMY16_8 },
+ { BFD_RELOC_32_PCREL, R_XSTORMY16_PC32 },
+ { BFD_RELOC_16_PCREL, R_XSTORMY16_PC16 },
+ { BFD_RELOC_8_PCREL, R_XSTORMY16_PC8 },
+ { BFD_RELOC_XSTORMY16_REL_12, R_XSTORMY16_REL_12 },
+ { BFD_RELOC_XSTORMY16_24, R_XSTORMY16_24 },
+ { BFD_RELOC_XSTORMY16_FPTR16, R_XSTORMY16_FPTR16 },
+ { BFD_RELOC_VTABLE_INHERIT, R_XSTORMY16_GNU_VTINHERIT },
+ { BFD_RELOC_VTABLE_ENTRY, R_XSTORMY16_GNU_VTENTRY },
+};
+
+static reloc_howto_type *
+xstormy16_reloc_type_lookup (abfd, code)
+ bfd * abfd ATTRIBUTE_UNUSED;
+ bfd_reloc_code_real_type code;
+{
+ unsigned int i;
+
+ for (i = sizeof (xstormy16_reloc_map) / sizeof (xstormy16_reloc_map[0]);
+ --i;)
+ if (xstormy16_reloc_map [i].bfd_reloc_val == code)
+ return & xstormy16_elf_howto_table [xstormy16_reloc_map[i].xstormy16_reloc_val];
+
+ return NULL;
+}
+
+/* Set the howto pointer for an XSTORMY16 ELF reloc. */
+
+static void
+xstormy16_info_to_howto_rela (abfd, cache_ptr, dst)
+ bfd * abfd ATTRIBUTE_UNUSED;
+ arelent * cache_ptr;
+ Elf32_Internal_Rela * dst;
+{
+ unsigned int r_type = ELF32_R_TYPE (dst->r_info);
+
+ if (r_type <= (unsigned int) R_XSTORMY16_FPTR16)
+ cache_ptr->howto = &xstormy16_elf_howto_table [r_type];
+ else if (r_type - R_XSTORMY16_GNU_VTINHERIT
+ <= (unsigned int) R_XSTORMY16_GNU_VTENTRY)
+ cache_ptr->howto
+ = &xstormy16_elf_howto_table2 [r_type - R_XSTORMY16_GNU_VTINHERIT];
+ else
+ abort ();
+}
+
+/* Handle the R_XSTORMY16_24 reloc, which has an odd bit arrangement. */
+
+static bfd_reloc_status_type
+xstormy16_elf_24_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;
+{
+ bfd_vma relocation, x;
+
+ if (output_bfd != NULL)
+ {
+ reloc_entry->address += input_section->output_offset;
+ return bfd_reloc_ok;
+ }
+
+ if (reloc_entry->address > input_section->_cooked_size)
+ return bfd_reloc_outofrange;
+
+ if (bfd_is_com_section (symbol->section))
+ relocation = 0;
+ else
+ relocation = symbol->value;
+
+ relocation += symbol->section->output_section->vma;
+ relocation += symbol->section->output_offset;
+ relocation += reloc_entry->addend;
+
+ x = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
+ x &= 0x0000ff00;
+ x |= relocation & 0xff;
+ x |= (relocation << 8) & 0xffff0000;
+ bfd_put_32 (abfd, x, (bfd_byte *) data + reloc_entry->address);
+
+ if (relocation & ~ (bfd_vma) 0xffffff)
+ return bfd_reloc_overflow;
+
+ return bfd_reloc_ok;
+}
+
+/* We support 16-bit pointers to code above 64k by generating a thunk
+ below 64k containing a JMPF instruction to the final address. We
+ cannot, unfortunately, minimize the number of thunks unless the
+ -relax switch is given, as otherwise we have no idea where the
+ sections will fall in the address space. */
+
+static boolean
+xstormy16_elf_check_relocs (abfd, info, sec, relocs)
+ bfd *abfd;
+ struct bfd_link_info *info;
+ asection *sec;
+ const Elf_Internal_Rela *relocs;
+{
+ const Elf_Internal_Rela *rel, *relend;
+ struct elf_link_hash_entry **sym_hashes;
+ Elf_Internal_Shdr *symtab_hdr;
+ bfd_vma *local_plt_offsets;
+ asection *splt;
+ bfd *dynobj;
+
+ if (info->relocateable)
+ return true;
+
+ symtab_hdr = &elf_tdata(abfd)->symtab_hdr;
+ sym_hashes = elf_sym_hashes (abfd);
+ local_plt_offsets = elf_local_got_offsets (abfd);
+ splt = NULL;
+ dynobj = elf_hash_table(info)->dynobj;
+
+ relend = relocs + sec->reloc_count;
+ for (rel = relocs; rel < relend; ++rel)
+ {
+ unsigned long r_symndx;
+ struct elf_link_hash_entry *h;
+ bfd_vma *offset;
+
+ 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;
+ }
+
+ switch (ELF32_R_TYPE (rel->r_info))
+ {
+ /* This relocation describes a 16-bit pointer to a function.
+ We may need to allocate a thunk in low memory; reserve memory
+ for it now. */
+ case R_XSTORMY16_FPTR16:
+ if (rel->r_addend != 0)
+ {
+ (*info->callbacks->warning)
+ (info, _("non-zero addend in @fptr reloc"), 0,
+ abfd, 0, 0);
+ }
+
+ if (dynobj == NULL)
+ elf_hash_table (info)->dynobj = dynobj = abfd;
+ if (splt == NULL)
+ {
+ splt = bfd_get_section_by_name (dynobj, ".plt");
+ if (splt == NULL)
+ {
+ splt = bfd_make_section (dynobj, ".plt");
+ if (splt == NULL
+ || ! bfd_set_section_flags (dynobj, splt,
+ (SEC_ALLOC
+ | SEC_LOAD
+ | SEC_HAS_CONTENTS
+ | SEC_IN_MEMORY
+ | SEC_LINKER_CREATED
+ | SEC_READONLY
+ | SEC_CODE))
+ || ! bfd_set_section_alignment (dynobj, splt, 1))
+ return false;
+ }
+ }
+
+ if (h != NULL)
+ offset = &h->plt.offset;
+ else
+ {
+ if (local_plt_offsets == NULL)
+ {
+ size_t size;
+ unsigned int i;
+
+ size = symtab_hdr->sh_info * sizeof (bfd_vma);
+ local_plt_offsets = (bfd_vma *) bfd_alloc (abfd, size);
+ if (local_plt_offsets == NULL)
+ return false;
+ elf_local_got_offsets (abfd) = local_plt_offsets;
+
+ for (i = 0; i < symtab_hdr->sh_info; i++)
+ local_plt_offsets[i] = (bfd_vma) -1;
+ }
+ offset = &local_plt_offsets[r_symndx];
+ }
+
+ if (*offset == (bfd_vma) -1)
+ {
+ *offset = splt->_raw_size;
+ splt->_raw_size += 4;
+ }
+ break;
+
+ /* This relocation describes the C++ object vtable hierarchy.
+ Reconstruct it for later use during GC. */
+ case R_XSTORMY16_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_XSTORMY16_GNU_VTENTRY:
+ if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_addend))
+ return false;
+ break;
+ }
+ }
+
+ return true;
+}
+
+/* A subroutine of xstormy16_elf_relax_section. If the global symbol H
+ is within the low 64k, remove any entry for it in the plt. */
+
+struct relax_plt_data
+{
+ asection *splt;
+ boolean *again;
+};
+
+static boolean
+xstormy16_relax_plt_check (h, xdata)
+ struct elf_link_hash_entry *h;
+ PTR xdata;
+{
+ struct relax_plt_data *data = (struct relax_plt_data *) xdata;
+
+ if (h->plt.offset != (bfd_vma) -1)
+ {
+ bfd_vma address;
+
+ if (h->root.type == bfd_link_hash_undefined
+ || h->root.type == bfd_link_hash_undefweak)
+ address = 0;
+ else
+ address = (h->root.u.def.section->output_section->vma
+ + h->root.u.def.section->output_offset
+ + h->root.u.def.value);
+
+ if (address <= 0xffff)
+ {
+ h->plt.offset = -1;
+ data->splt->_cooked_size -= 4;
+ *data->again = true;
+ }
+ }
+
+ return true;
+}
+
+/* A subroutine of xstormy16_elf_relax_section. If the global symbol H
+ previously had a plt entry, give it a new entry offset. */
+
+static boolean
+xstormy16_relax_plt_realloc (h, xdata)
+ struct elf_link_hash_entry *h;
+ PTR xdata;
+{
+ bfd_vma *entry = (bfd_vma *) xdata;
+
+ if (h->plt.offset != (bfd_vma) -1)
+ {
+ h->plt.offset = *entry;
+ *entry += 4;
+ }
+
+ return true;
+}
+
+static boolean
+xstormy16_elf_relax_section (dynobj, splt, info, again)
+ bfd *dynobj;
+ asection *splt;
+ struct bfd_link_info *info;
+ boolean *again;
+{
+ struct relax_plt_data relax_plt_data;
+ bfd *ibfd;
+
+ /* Assume nothing changes. */
+ *again = false;
+
+ if (info->relocateable)
+ return true;
+
+ /* We only relax the .plt section at the moment. */
+ if (dynobj != elf_hash_table (info)->dynobj
+ || strcmp (splt->name, ".plt") != 0)
+ return true;
+
+ /* Quick check for an empty plt. */
+ if (splt->_raw_size == 0)
+ return true;
+
+ /* If this is the first time we have been called for this section,
+ initialize the cooked size. */
+ if (splt->_cooked_size == 0)
+ splt->_cooked_size = splt->_raw_size;
+
+ /* Map across all global symbols; see which ones happen to
+ fall in the low 64k. */
+ relax_plt_data.splt = splt;
+ relax_plt_data.again = again;
+ elf_link_hash_traverse (elf_hash_table (info), xstormy16_relax_plt_check,
+ &relax_plt_data);
+
+ /* Likewise for local symbols, though that's somewhat less convenient
+ as we have walk the list of input bfds and swap in symbol data. */
+ for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link_next)
+ {
+ bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd);
+ Elf_Internal_Shdr *symtab_hdr;
+ Elf32_External_Sym *extsyms;
+ unsigned int idx;
+
+ if (! local_plt_offsets)
+ continue;
+
+ symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
+
+ if (symtab_hdr->contents != NULL)
+ extsyms = (Elf32_External_Sym *) symtab_hdr->contents;
+ else
+ {
+ extsyms = (Elf32_External_Sym *) bfd_malloc (symtab_hdr->sh_size);
+ if (extsyms == NULL)
+ return false;
+ if (bfd_seek (ibfd, symtab_hdr->sh_offset, SEEK_SET) != 0
+ || (bfd_bread (extsyms, symtab_hdr->sh_size, ibfd)
+ != symtab_hdr->sh_size))
+ {
+ free (extsyms);
+ return false;
+ }
+ }
+
+ for (idx = 0; idx < symtab_hdr->sh_info; ++idx)
+ {
+ Elf_Internal_Sym isym;
+ asection *tsec;
+ bfd_vma address;
+
+ if (local_plt_offsets[idx] == (bfd_vma) -1)
+ continue;
+
+ bfd_elf32_swap_symbol_in (ibfd, extsyms + idx, &isym);
+ if (isym.st_shndx == SHN_UNDEF)
+ continue;
+ else if (isym.st_shndx > 0 && isym.st_shndx < SHN_LORESERVE)
+ tsec = bfd_section_from_elf_index (ibfd, isym.st_shndx);
+ else if (isym.st_shndx == SHN_ABS)
+ tsec = bfd_abs_section_ptr;
+ else
+ continue;
+
+ address = (tsec->output_section->vma
+ + tsec->output_offset
+ + isym.st_value);
+ if (address <= 0xffff)
+ {
+ local_plt_offsets[idx] = -1;
+ splt->_cooked_size -= 4;
+ *again = true;
+ }
+ }
+
+ if (symtab_hdr->contents != extsyms)
+ free (extsyms);
+ }
+
+ /* If we changed anything, walk the symbols again to reallocate
+ .plt entry addresses. */
+ if (*again && splt->_cooked_size > 0)
+ {
+ bfd_vma entry = 0;
+
+ elf_link_hash_traverse (elf_hash_table (info),
+ xstormy16_relax_plt_realloc, &entry);
+
+ for (ibfd = info->input_bfds; ibfd ; ibfd = ibfd->link_next)
+ {
+ bfd_vma *local_plt_offsets = elf_local_got_offsets (ibfd);
+ unsigned int nlocals = elf_tdata (ibfd)->symtab_hdr.sh_info;
+ unsigned int idx;
+
+ if (! local_plt_offsets)
+ continue;
+
+ for (idx = 0; idx < nlocals; ++idx)
+ if (local_plt_offsets[idx] != (bfd_vma) -1)
+ {
+ local_plt_offsets[idx] = entry;
+ entry += 4;
+ }
+ }
+ }
+
+ splt->_raw_size = splt->_cooked_size;
+ return true;
+}
+
+static boolean
+xstormy16_elf_always_size_sections (output_bfd, info)
+ bfd *output_bfd ATTRIBUTE_UNUSED;
+ struct bfd_link_info *info;
+{
+ bfd *dynobj;
+ asection *splt;
+
+ if (info->relocateable)
+ return true;
+
+ dynobj = elf_hash_table (info)->dynobj;
+ if (dynobj == NULL)
+ return true;
+
+ splt = bfd_get_section_by_name (dynobj, ".plt");
+ BFD_ASSERT (splt != NULL);
+
+ splt->contents = (bfd_byte *) bfd_zalloc (dynobj, splt->_raw_size);
+ if (splt->contents == NULL)
+ return false;
+
+ return true;
+}
+
+/* Relocate an XSTORMY16 ELF section.
+ There is some attempt to make this function usable for many architectures,
+ both USE_REL and USE_RELA ['twould be nice if such a critter existed],
+ if only to serve as a learning tool.
+
+ The RELOCATE_SECTION function is called by the new ELF backend linker
+ to handle the relocations for a section.
+
+ The relocs are always passed as Rela structures; if the section
+ actually uses Rel structures, the r_addend field will always be
+ zero.
+
+ This function is responsible for adjusting the section contents as
+ necessary, and (if using Rela relocs and generating a relocateable
+ output file) adjusting the reloc addend as necessary.
+
+ This function does not have to worry about setting the reloc
+ address or the reloc symbol index.
+
+ LOCAL_SYMS is a pointer to the swapped in local symbols.
+
+ LOCAL_SECTIONS is an array giving the section in the input file
+ corresponding to the st_shndx field of each local symbol.
+
+ The global hash table entry for the global symbols can be found
+ via elf_sym_hashes (input_bfd).
+
+ When generating relocateable output, this function must handle
+ STB_LOCAL/STT_SECTION symbols specially. The output symbol is
+ going to be the section symbol corresponding to the output
+ section, which means that the addend must be adjusted
+ accordingly. */
+
+static boolean
+xstormy16_elf_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;
+ Elf_Internal_Rela * relend;
+ bfd *dynobj;
+ asection *splt;
+
+ symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
+ sym_hashes = elf_sym_hashes (input_bfd);
+ relend = relocs + input_section->reloc_count;
+
+ dynobj = elf_hash_table (info)->dynobj;
+ splt = NULL;
+ if (dynobj != NULL)
+ splt = bfd_get_section_by_name (dynobj, ".plt");
+
+ for (rel = relocs; rel < relend; rel ++)
+ {
+ 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;
+ const char * name = NULL;
+ int r_type;
+
+ r_type = ELF32_R_TYPE (rel->r_info);
+
+ if ( r_type == R_XSTORMY16_GNU_VTINHERIT
+ || r_type == R_XSTORMY16_GNU_VTENTRY)
+ continue;
+
+ r_symndx = ELF32_R_SYM (rel->r_info);
+
+ 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. */
+ howto = xstormy16_elf_howto_table + ELF32_R_TYPE (rel->r_info);
+ 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);
+
+ name = bfd_elf_string_from_elf_section
+ (input_bfd, symtab_hdr->sh_link, sym->st_name);
+ name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
+ }
+ 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;
+
+ name = h->root.root.string;
+
+ 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;
+ }
+ }
+
+ switch (ELF32_R_TYPE (rel->r_info))
+ {
+ case R_XSTORMY16_24:
+ {
+ bfd_vma reloc = relocation + rel->r_addend;
+ unsigned int x;
+
+ x = bfd_get_32 (input_bfd, contents + rel->r_offset);
+ x &= 0x0000ff00;
+ x |= reloc & 0xff;
+ x |= (reloc << 8) & 0xffff0000;
+ bfd_put_32 (input_bfd, x, contents + rel->r_offset);
+
+ if (reloc & ~0xffffff)
+ r = bfd_reloc_overflow;
+ else
+ r = bfd_reloc_ok;
+ break;
+ }
+
+ case R_XSTORMY16_FPTR16:
+ {
+ bfd_vma *plt_offset;
+
+ if (h != NULL)
+ plt_offset = &h->plt.offset;
+ else
+ plt_offset = elf_local_got_offsets (input_bfd) + r_symndx;
+
+ if (relocation <= 0xffff)
+ {
+ /* If the symbol is in range for a 16-bit address, we should
+ have deallocated the plt entry in relax_section. */
+ BFD_ASSERT (*plt_offset == (bfd_vma) -1);
+ }
+ else
+ {
+ /* If the symbol is out of range for a 16-bit address,
+ we must have allocated a plt entry. */
+ BFD_ASSERT (*plt_offset != (bfd_vma) -1);
+
+ /* If this is the first time we've processed this symbol,
+ fill in the plt entry with the correct symbol address. */
+ if ((*plt_offset & 1) == 0)
+ {
+ unsigned int x;
+
+ x = 0x00000200; /* jmpf */
+ x |= relocation & 0xff;
+ x |= (relocation << 8) & 0xffff0000;
+ bfd_put_32 (input_bfd, x, splt->contents + *plt_offset);
+ *plt_offset |= 1;
+ }
+
+ relocation = (splt->output_section->vma
+ + splt->output_offset
+ + (*plt_offset & -2));
+ }
+ r = _bfd_final_link_relocate (howto, input_bfd, input_section,
+ contents, rel->r_offset,
+ relocation, 0);
+ break;
+ }
+
+ default:
+ r = _bfd_final_link_relocate (howto, input_bfd, input_section,
+ contents, rel->r_offset,
+ relocation, rel->r_addend);
+ break;
+ }
+
+ if (r != bfd_reloc_ok)
+ {
+ const char * msg = (const char *) NULL;
+
+ switch (r)
+ {
+ case bfd_reloc_overflow:
+ r = info->callbacks->reloc_overflow
+ (info, name, howto->name, (bfd_vma) 0,
+ input_bfd, input_section, rel->r_offset);
+ break;
+
+ case bfd_reloc_undefined:
+ r = info->callbacks->undefined_symbol
+ (info, name, input_bfd, input_section, rel->r_offset,
+ true);
+ break;
+
+ case bfd_reloc_outofrange:
+ msg = _("internal error: out of range error");
+ break;
+
+ case bfd_reloc_notsupported:
+ msg = _("internal error: unsupported relocation error");
+ break;
+
+ case bfd_reloc_dangerous:
+ msg = _("internal error: dangerous relocation");
+ break;
+
+ default:
+ msg = _("internal error: unknown error");
+ break;
+ }
+
+ if (msg)
+ r = info->callbacks->warning
+ (info, msg, name, input_bfd, input_section, rel->r_offset);
+
+ if (! r)
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/* This must exist if dynobj is ever set. */
+
+static boolean
+xstormy16_elf_finish_dynamic_sections (abfd, info)
+ bfd *abfd ATTRIBUTE_UNUSED;
+ struct bfd_link_info *info;
+{
+ bfd *dynobj;
+ asection *splt;
+
+ /* As an extra sanity check, verify that all plt entries have
+ been filled in. */
+
+ if ((dynobj = elf_hash_table (info)->dynobj) != NULL
+ && (splt = bfd_get_section_by_name (dynobj, ".plt")) != NULL)
+ {
+ bfd_byte *contents = splt->contents;
+ unsigned int i, size = splt->_raw_size;
+ for (i = 0; i < size; i += 4)
+ {
+ unsigned int x = bfd_get_32 (dynobj, contents + i);
+ BFD_ASSERT (x != 0);
+ }
+ }
+
+ return true;
+}
+
+/* Return the section that should be marked against GC for a given
+ relocation. */
+
+static asection *
+xstormy16_elf_gc_mark_hook (abfd, info, rel, h, sym)
+ bfd * abfd;
+ 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))
+ {
+ case R_XSTORMY16_GNU_VTINHERIT:
+ case R_XSTORMY16_GNU_VTENTRY:
+ break;
+
+ default:
+ switch (h->root.type)
+ {
+ case bfd_link_hash_defined:
+ case bfd_link_hash_defweak:
+ return h->root.u.def.section;
+
+ case bfd_link_hash_common:
+ return h->root.u.c.p->section;
+
+ default:
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (!(elf_bad_symtab (abfd)
+ && ELF_ST_BIND (sym->st_info) != STB_LOCAL)
+ && ! ((sym->st_shndx <= 0 || sym->st_shndx >= SHN_LORESERVE)
+ && sym->st_shndx != SHN_COMMON))
+ {
+ return bfd_section_from_elf_index (abfd, sym->st_shndx);
+ }
+ }
+
+ return NULL;
+}
+
+/* Update the got entry reference counts for the section being removed. */
+
+static boolean
+xstormy16_elf_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;
+{
+ return true;
+}
+
+#define ELF_ARCH bfd_arch_xstormy16
+#define ELF_MACHINE_CODE EM_XSTORMY16
+#define ELF_MAXPAGESIZE 0x100
+
+#define TARGET_LITTLE_SYM bfd_elf32_xstormy16_vec
+#define TARGET_LITTLE_NAME "elf32-xstormy16"
+
+#define elf_info_to_howto_rel NULL
+#define elf_info_to_howto xstormy16_info_to_howto_rela
+#define elf_backend_relocate_section xstormy16_elf_relocate_section
+#define elf_backend_gc_mark_hook xstormy16_elf_gc_mark_hook
+#define elf_backend_gc_sweep_hook xstormy16_elf_gc_sweep_hook
+#define elf_backend_check_relocs xstormy16_elf_check_relocs
+#define elf_backend_always_size_sections \
+ xstormy16_elf_always_size_sections
+#define elf_backend_finish_dynamic_sections \
+ xstormy16_elf_finish_dynamic_sections
+
+#define elf_backend_can_gc_sections 1
+
+#define bfd_elf32_bfd_reloc_type_lookup xstormy16_reloc_type_lookup
+#define bfd_elf32_bfd_relax_section xstormy16_elf_relax_section
+
+#include "elf32-target.h"