2000-12-03 Kazu Hirata <kazu@hxi.com>
[deliverable/binutils-gdb.git] / bfd / coff-arm.c
index 3136a8d15c40c526ee9a63740a7c36856df9a145..95e65cd43cddf0332abeae1f80eb91fe74e283ee 100644 (file)
@@ -1,5 +1,6 @@
-/* BFD back-end for Intel arm COFF files.
-   Copyright 1990, 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+/* BFD back-end for ARM COFF files.
+   Copyright 1990, 91, 92, 93, 94, 95, 96, 97, 98, 99, 2000
+   Free Software Foundation, Inc.
    Written by Cygnus Support.
 
 This file is part of BFD, the Binary File Descriptor library.
@@ -21,7 +22,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #include "bfd.h"
 #include "sysdep.h"
 #include "libbfd.h"
-#include "obstack.h"
 
 #include "coff/arm.h"
 
@@ -33,274 +33,559 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 #include "libcoff.h"
 
-static bfd_reloc_status_type
-aoutarm_fix_pcrel_26_done PARAMS ((bfd *, arelent *, asymbol *, PTR,
-                                 asection *, bfd *, char **));
-
-static bfd_reloc_status_type
-aoutarm_fix_pcrel_26 PARAMS ((bfd *, arelent *, asymbol *, PTR,
-                            asection *, bfd *, char **));
+/* Macros for manipulation the bits in the flags field of the coff data
+   structure.  */
+#define APCS_26_FLAG(       abfd )     (coff_data (abfd)->flags & F_APCS_26)
+#define APCS_FLOAT_FLAG(    abfd )     (coff_data (abfd)->flags & F_APCS_FLOAT)
+#define PIC_FLAG(           abfd )     (coff_data (abfd)->flags & F_PIC)
+#define APCS_SET(           abfd )     (coff_data (abfd)->flags & F_APCS_SET)
+#define SET_APCS_FLAGS(     abfd, flgs)        (coff_data (abfd)->flags = \
+                                       (coff_data (abfd)->flags & ~ (F_APCS_26 | F_APCS_FLOAT | F_PIC)) \
+                                        | (flgs | F_APCS_SET))
+#define INTERWORK_FLAG(     abfd )     (coff_data (abfd)->flags & F_INTERWORK)
+#define INTERWORK_SET(      abfd )     (coff_data (abfd)->flags & F_INTERWORK_SET)
+#define SET_INTERWORK_FLAG( abfd, flg )        (coff_data (abfd)->flags = \
+                                       (coff_data (abfd)->flags & ~ F_INTERWORK) \
+                                        | (flg | F_INTERWORK_SET))
+
+#ifndef NUM_ELEM
+#define NUM_ELEM(a) ((sizeof (a)) / sizeof ((a)[0]))
+#endif
 
+typedef enum {bunknown, b9, b12, b23} thumb_pcrel_branchtype;
+/* some typedefs for holding instructions */
+typedef unsigned long int insn32;
+typedef unsigned short int insn16;
 
-static bfd_reloc_status_type coff_arm_reloc 
+     /* Forward declarations for stupid compilers.  */
+static boolean coff_arm_relocate_section
+  PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
+           struct internal_reloc *, struct internal_syment *, asection **));
+static bfd_reloc_status_type aoutarm_fix_pcrel_26_done
   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
-
+static bfd_reloc_status_type aoutarm_fix_pcrel_26
+  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+static bfd_reloc_status_type coff_thumb_pcrel_23
+  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+static bfd_reloc_status_type coff_thumb_pcrel_12
+  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+static bfd_reloc_status_type coff_thumb_pcrel_9
+  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+static bfd_reloc_status_type coff_arm_reloc
+  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+static boolean coff_arm_adjust_symndx
+  PARAMS ((bfd *, struct bfd_link_info *, bfd *,
+          asection *, struct internal_reloc *, boolean *));
+static reloc_howto_type * coff_arm_rtype_to_howto
+  PARAMS ((bfd *, asection *, struct internal_reloc *,
+          struct coff_link_hash_entry *, struct internal_syment *, bfd_vma *));
+static bfd_reloc_status_type coff_thumb_pcrel_common
+  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **,
+          thumb_pcrel_branchtype));
+static CONST struct reloc_howto_struct * coff_arm_reloc_type_lookup
+  PARAMS ((bfd *, bfd_reloc_code_real_type));
+static struct bfd_link_hash_table * coff_arm_link_hash_table_create
+  PARAMS ((bfd *));
+static insn32 insert_thumb_branch
+  PARAMS ((insn32, int));
+static struct coff_link_hash_entry * find_thumb_glue
+  PARAMS ((struct bfd_link_info *, CONST char *, bfd *));
+static struct coff_link_hash_entry * find_arm_glue
+  PARAMS ((struct bfd_link_info *, CONST char *, bfd *));
+#ifndef COFF_IMAGE_WITH_PE
+static void record_arm_to_thumb_glue
+  PARAMS ((struct bfd_link_info *, struct coff_link_hash_entry *));
+static void record_thumb_to_arm_glue
+  PARAMS ((struct bfd_link_info *, struct coff_link_hash_entry *));
+#endif
+static boolean coff_arm_merge_private_bfd_data
+  PARAMS ((bfd *, bfd *));
+static boolean coff_arm_print_private_bfd_data
+  PARAMS ((bfd *, PTR));
+static boolean _bfd_coff_arm_set_private_flags
+  PARAMS ((bfd *, flagword));
+static boolean coff_arm_copy_private_bfd_data
+  PARAMS ((bfd *, bfd *));
+static boolean coff_arm_is_local_label_name
+  PARAMS ((bfd *, const char *));
+static boolean coff_arm_link_output_has_begun
+  PARAMS ((bfd *, struct coff_final_link_info *));
+static boolean coff_arm_final_link_postscript
+  PARAMS ((bfd *, struct coff_final_link_info *));
+
+/* The linker script knows the section names for placement.
+   The entry_names are used to do simple name mangling on the stubs.
+   Given a function name, and its type, the stub can be found. The
+   name can be changed. The only requirement is the %s be present.
+   */
+
+#define THUMB2ARM_GLUE_SECTION_NAME ".glue_7t"
+#define THUMB2ARM_GLUE_ENTRY_NAME   "__%s_from_thumb"
+
+#define ARM2THUMB_GLUE_SECTION_NAME ".glue_7"
+#define ARM2THUMB_GLUE_ENTRY_NAME   "__%s_from_arm"
+
+/* Used by the assembler.  */
 static bfd_reloc_status_type
 coff_arm_reloc (abfd, reloc_entry, symbol, data, input_section, output_bfd,
                 error_message)
      bfd *abfd;
      arelent *reloc_entry;
-     asymbol *symbol;
+     asymbol *symbol ATTRIBUTE_UNUSED;
      PTR data;
-     asection *input_section;
+     asection *input_section ATTRIBUTE_UNUSED;
      bfd *output_bfd;
-     char **error_message;
+     char **error_message ATTRIBUTE_UNUSED;
 {
   symvalue diff;
-
   if (output_bfd == (bfd *) NULL)
     return bfd_reloc_continue;
 
-  if (bfd_is_com_section (symbol->section))
-    {
-      /* We are relocating a common symbol.  The current value in the
-        object file is ORIG + OFFSET, where ORIG is the value of the
-        common symbol as seen by the object file when it was compiled
-        (this may be zero if the symbol was undefined) and OFFSET is
-        the offset into the common symbol (normally zero, but may be
-        non-zero when referring to a field in a common structure).
-        ORIG is the negative of reloc_entry->addend, which is set by
-        the CALC_ADDEND macro below.  We want to replace the value in
-        the object file with NEW + OFFSET, where NEW is the value of
-        the common symbol which we are going to put in the final
-        object file.  NEW is symbol->value.  */
-      diff = symbol->value + reloc_entry->addend;
-    }
-  else
-    {
-      /* For some reason bfd_perform_relocation always effectively
-        ignores the addend for a COFF target when producing
-        relocateable output.  This seems to be always wrong for 386
-        COFF, so we handle the addend here instead.  */
-      diff = reloc_entry->addend;
-    }
+  diff = reloc_entry->addend;
 
 #define DOIT(x) \
   x = ((x & ~howto->dst_mask) | (((x & howto->src_mask) + diff) & howto->dst_mask))
 
-  if (diff != 0)
-    {
-      reloc_howto_type *howto = reloc_entry->howto;
-      unsigned char *addr = (unsigned char *) data + reloc_entry->address;
-
-      switch (howto->size)
-       {
-       case 0:
-         {
-           char x = bfd_get_8 (abfd, addr);
-           DOIT (x);
-           bfd_put_8 (abfd, x, addr);
-         }
-         break;
-
-       case 1:
-         {
-           short x = bfd_get_16 (abfd, addr);
-           DOIT (x);
-           bfd_put_16 (abfd, x, addr);
-         }
-         break;
+    if (diff != 0)
+      {
+       reloc_howto_type *howto = reloc_entry->howto;
+       unsigned char *addr = (unsigned char *) data + reloc_entry->address;
 
-       case 2:
+       switch (howto->size)
          {
-           long x = bfd_get_32 (abfd, addr);
-           DOIT (x);
-           bfd_put_32 (abfd, x, addr);
+         case 0:
+           {
+             char x = bfd_get_8 (abfd, addr);
+             DOIT (x);
+             bfd_put_8 (abfd, x, addr);
+           }
+           break;
+
+         case 1:
+           {
+             short x = bfd_get_16 (abfd, addr);
+             DOIT (x);
+             bfd_put_16 (abfd, x, addr);
+           }
+           break;
+
+         case 2:
+           {
+             long x = bfd_get_32 (abfd, addr);
+             DOIT (x);
+             bfd_put_32 (abfd, x, addr);
+           }
+           break;
+
+         default:
+           abort ();
          }
-         break;
-
-       default:
-         abort ();
-       }
-    }
+      }
 
   /* Now let bfd_perform_relocation finish everything up.  */
   return bfd_reloc_continue;
 }
 
+/* If USER_LABEL_PREFIX is defined as "_" (see coff_arm_is_local_label_name()
+   in this file), then TARGET_UNDERSCORE should be defined, otherwise it
+   should not.  */
+#ifndef TARGET_UNDERSCORE
+#define TARGET_UNDERSCORE '_'
+#endif
+
 #ifndef PCRELOFFSET
 #define PCRELOFFSET true
 #endif
 
-static reloc_howto_type aoutarm_std_reloc_howto[] = 
+/* These most certainly belong somewhere else. Just had to get rid of
+   the manifest constants in the code.  */
+#define ARM_8        0
+#define ARM_16       1
+#define ARM_32       2
+#define ARM_26       3
+#define ARM_DISP8    4
+#define ARM_DISP16   5
+#define ARM_DISP32   6
+#define ARM_26D      7
+/* 8 is unused */
+#define ARM_NEG16    9
+#define ARM_NEG32   10
+#define ARM_RVA32   11
+#define ARM_THUMB9  12
+#define ARM_THUMB12 13
+#define ARM_THUMB23 14
+
+#ifdef ARM_WINCE
+#undef  ARM_32
+#undef  ARM_RVA32
+#undef  ARM_26
+#undef  ARM_THUMB12
+#undef  ARM_26D
+
+#define ARM_32       1
+#define ARM_RVA32    2
+#define ARM_26      3
+#define ARM_THUMB12  4
+#define ARM_26D      5
+#define ARM_SECTION  14
+#define ARM_SECREL   15
+#endif
+
+static reloc_howto_type aoutarm_std_reloc_howto[] =
 {
   /* type              rs size bsz  pcrel bitpos ovrf                     sf name     part_inpl readmask  setmask    pcdone */
-  HOWTO(0,                     /* type */
-       0,                      /* rs */
+#ifdef ARM_WINCE
+  EMPTY_HOWTO (-1),
+  HOWTO (ARM_32,
+       0,
+       2,
+       32,
+       false,
+       0,
+       complain_overflow_bitfield,
+       coff_arm_reloc,
+       "ARM_32",
+        true,
+       0xffffffff,
+       0xffffffff,
+       PCRELOFFSET),
+  HOWTO (ARM_RVA32,
+       0,
+       2,
+       32,
+       false,
+       0,
+       complain_overflow_bitfield,
+       coff_arm_reloc,
+       "ARM_RVA32",
+        true,
+       0xffffffff,
+       0xffffffff,
+       PCRELOFFSET),
+  HOWTO (ARM_26,
+       2,
+       2,
+       24,
+       true,
+       0,
+       complain_overflow_signed,
+       aoutarm_fix_pcrel_26 ,
+       "ARM_26",
+       false,
+       0x00ffffff,
+       0x00ffffff,
+       PCRELOFFSET),
+  HOWTO (ARM_THUMB12,
+       1,
+       1,
+       11,
+       true,
+       0,
+       complain_overflow_signed,
+       coff_thumb_pcrel_12 ,
+       "ARM_THUMB12",
+       false,
+       0x000007ff,
+       0x000007ff,
+       PCRELOFFSET),
+  HOWTO (ARM_26D,
+       2,
+       2,
+       24,
+       false,
+       0,
+       complain_overflow_dont,
+       aoutarm_fix_pcrel_26_done,
+       "ARM_26D",
+       true,
+       0x00ffffff,
+       0x0,
+       false),
+  EMPTY_HOWTO (-1),
+  EMPTY_HOWTO (-1),
+  EMPTY_HOWTO (-1),
+  EMPTY_HOWTO (-1),
+  EMPTY_HOWTO (-1),
+  EMPTY_HOWTO (-1),
+  EMPTY_HOWTO (-1),
+  EMPTY_HOWTO (-1),
+  HOWTO (ARM_SECTION,
+       0,
+       1,
+       16,
+       false,
+       0,
+       complain_overflow_bitfield,
+       coff_arm_reloc,
+       "ARM_16",
+       true,
+       0x0000ffff,
+       0x0000ffff,
+       PCRELOFFSET),
+  HOWTO (ARM_SECREL,
+       0,
+       2,
+       32,
+       false,
+       0,
+       complain_overflow_bitfield,
+       coff_arm_reloc,
+       "ARM_32",
+        true,
+       0xffffffff,
+       0xffffffff,
+       PCRELOFFSET),
+#else /* not ARM_WINCE */
+  HOWTO(ARM_8,                 /* type */
+       0,                      /* rightshift */
        0,                      /* size */
-       8,                      /* bsz */
-       false,                  /* pcrel */
+       8,                      /* bitsize */
+       false,                  /* pc_relative */
        0,                      /* bitpos */
-       complain_overflow_bitfield, /* ovf */
-       coff_arm_reloc,         /* sf */
-       "8",                    /*name */
-        true,                  /* partial */
-       0x000000ff,             /*read mask */
-       0x000000ff,             /* setmask */
-       PCRELOFFSET             /* pcdone */),
-  HOWTO(1,  
-       0, 
-       1, 
-       16, 
+       complain_overflow_bitfield, /* complain_on_overflow */
+       coff_arm_reloc,         /* special_function */
+       "ARM_8",                /* name */
+        true,                  /* partial_inplace */
+       0x000000ff,             /* src_mask */
+       0x000000ff,             /* dst_mask */
+       PCRELOFFSET             /* pcrel_offset */),
+  HOWTO(ARM_16,
+       0,
+       1,
+       16,
        false,
        0,
        complain_overflow_bitfield,
        coff_arm_reloc,
-       "16", 
+       "ARM_16",
        true,
        0x0000ffff,
-       0x0000ffff, 
+       0x0000ffff,
        PCRELOFFSET),
-  HOWTO( 2, 
+  HOWTO(ARM_32,
        0,
-       2, 
+       2,
        32,
        false,
        0,
        complain_overflow_bitfield,
        coff_arm_reloc,
-       "32",
+       "ARM_32",
         true,
        0xffffffff,
        0xffffffff,
        PCRELOFFSET),
-  HOWTO( 3,
+  HOWTO(ARM_26,
        2,
        2,
-       26,
+       24,
        true,
        0,
        complain_overflow_signed,
        aoutarm_fix_pcrel_26 ,
-       "ARM26",
-       true, 
+       "ARM_26",
+       false,
+       0x00ffffff,
        0x00ffffff,
-       0x00ffffff, 
        PCRELOFFSET),
-  HOWTO( 4,        
+  HOWTO(ARM_DISP8,
        0,
        0,
-       8, 
+       8,
        true,
        0,
-       complain_overflow_signed, 
+       complain_overflow_signed,
        coff_arm_reloc,
-       "DISP8",  
+       "ARM_DISP8",
        true,
        0x000000ff,
        0x000000ff,
        true),
-  HOWTO( 5, 
+  HOWTO( ARM_DISP16,
        0,
        1,
        16,
        true,
        0,
-       complain_overflow_signed, 
+       complain_overflow_signed,
        coff_arm_reloc,
-       "DISP16",
+       "ARM_DISP16",
        true,
        0x0000ffff,
        0x0000ffff,
        true),
-  HOWTO( 6,
+  HOWTO( ARM_DISP32,
        0,
        2,
        32,
        true,
        0,
-       complain_overflow_signed, 
+       complain_overflow_signed,
        coff_arm_reloc,
-       "DISP32",
+       "ARM_DISP32",
        true,
        0xffffffff,
        0xffffffff,
        true),
-  HOWTO( 7,  
-       2, 
+  HOWTO( ARM_26D,
        2,
-       26,
+       2,
+       24,
        false,
        0,
-       complain_overflow_signed,
-       aoutarm_fix_pcrel_26_done, 
-       "ARM26D",
+       complain_overflow_dont,
+       aoutarm_fix_pcrel_26_done,
+       "ARM_26D",
        true,
        0x00ffffff,
-       0x00ffffff, 
+       0x0,
        false),
-  {-1},
-  HOWTO( 9,
+  /* 8 is unused */
+  EMPTY_HOWTO (-1),
+  HOWTO( ARM_NEG16,
        0,
        -1,
        16,
        false,
-       0, 
+       0,
        complain_overflow_bitfield,
        coff_arm_reloc,
-       "NEG16",
-        true, 
+       "ARM_NEG16",
+        true,
+       0x0000ffff,
        0x0000ffff,
-       0x0000ffff, 
        false),
-  HOWTO( 10, 
-       0, 
+  HOWTO( ARM_NEG32,
+       0,
        -2,
        32,
        false,
        0,
        complain_overflow_bitfield,
        coff_arm_reloc,
-       "NEG32",
+       "ARM_NEG32",
         true,
        0xffffffff,
        0xffffffff,
        false),
-  HOWTO( 11, 
+  HOWTO( ARM_RVA32,
        0,
-       2, 
+       2,
        32,
        false,
        0,
        complain_overflow_bitfield,
        coff_arm_reloc,
-       "rva32",
+       "ARM_RVA32",
         true,
        0xffffffff,
        0xffffffff,
        PCRELOFFSET),
+  HOWTO( ARM_THUMB9,
+       1,
+       1,
+       8,
+       true,
+       0,
+       complain_overflow_signed,
+       coff_thumb_pcrel_9 ,
+       "ARM_THUMB9",
+       false,
+       0x000000ff,
+       0x000000ff,
+       PCRELOFFSET),
+  HOWTO( ARM_THUMB12,
+       1,
+       1,
+       11,
+       true,
+       0,
+       complain_overflow_signed,
+       coff_thumb_pcrel_12 ,
+       "ARM_THUMB12",
+       false,
+       0x000007ff,
+       0x000007ff,
+       PCRELOFFSET),
+  HOWTO( ARM_THUMB23,
+       1,
+       2,
+       22,
+       true,
+       0,
+       complain_overflow_signed,
+       coff_thumb_pcrel_23 ,
+       "ARM_THUMB23",
+       false,
+       0x07ff07ff,
+       0x07ff07ff,
+       PCRELOFFSET)
+#endif /* not ARM_WINCE */
 };
 
+#define NUM_RELOCS NUM_ELEM (aoutarm_std_reloc_howto)
+
+#ifdef COFF_WITH_PE
+/* Return true if this relocation should
+   appear in the output .reloc section.  */
+
+static boolean
+in_reloc_p (abfd, howto)
+     bfd * abfd ATTRIBUTE_UNUSED;
+     reloc_howto_type * howto;
+{
+  return !howto->pc_relative && howto->type != ARM_RVA32;
+}
+#endif
+
+#define RTYPE2HOWTO(cache_ptr, dst)            \
+  (cache_ptr)->howto =                         \
+    (dst)->r_type < NUM_RELOCS                 \
+    ? aoutarm_std_reloc_howto + (dst)->r_type  \
+    : NULL
+
+#define coff_rtype_to_howto coff_arm_rtype_to_howto
+
+static reloc_howto_type *
+coff_arm_rtype_to_howto (abfd, sec, rel, h, sym, addendp)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     asection *sec;
+     struct internal_reloc *rel;
+     struct coff_link_hash_entry *h ATTRIBUTE_UNUSED;
+     struct internal_syment *sym ATTRIBUTE_UNUSED;
+     bfd_vma *addendp;
+{
+  reloc_howto_type * howto;
+
+  if (rel->r_type >= NUM_RELOCS)
+    return NULL;
 
+  howto = aoutarm_std_reloc_howto + rel->r_type;
 
-#define RTYPE2HOWTO(cache_ptr, dst) \
-           (cache_ptr)->howto = aoutarm_std_reloc_howto + (dst)->r_type;
+  if (rel->r_type == ARM_RVA32)
+    *addendp -= pe_data (sec->output_section->owner)->pe_opthdr.ImageBase;
+
+  return howto;
+}
+/* Used by the assembler.  */
 
 static bfd_reloc_status_type
 aoutarm_fix_pcrel_26_done (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;
+     bfd *abfd ATTRIBUTE_UNUSED;
+     arelent *reloc_entry ATTRIBUTE_UNUSED;
+     asymbol *symbol ATTRIBUTE_UNUSED;
+     PTR data ATTRIBUTE_UNUSED;
+     asection *input_section ATTRIBUTE_UNUSED;
+     bfd *output_bfd ATTRIBUTE_UNUSED;
+     char **error_message ATTRIBUTE_UNUSED;
 {
   /* This is dead simple at present.  */
   return bfd_reloc_ok;
 }
 
+/* Used by the assembler.  */
+
 static bfd_reloc_status_type
 aoutarm_fix_pcrel_26 (abfd, reloc_entry, symbol, data, input_section,
                     output_bfd, error_message)
@@ -310,13 +595,13 @@ aoutarm_fix_pcrel_26 (abfd, reloc_entry, symbol, data, input_section,
      PTR data;
      asection *input_section;
      bfd *output_bfd;
-     char **error_message;
+     char **error_message ATTRIBUTE_UNUSED;
 {
   bfd_vma relocation;
   bfd_size_type addr = reloc_entry->address;
   long target = bfd_get_32 (abfd, (bfd_byte *) data + addr);
   bfd_reloc_status_type flag = bfd_reloc_ok;
-  
+
   /* If this is an undefined symbol, return error */
   if (symbol->section == &bfd_und_section
       && (symbol->flags & BSF_WEAK) == 0)
@@ -337,13 +622,14 @@ aoutarm_fix_pcrel_26 (abfd, reloc_entry, symbol, data, input_section,
   relocation -= input_section->output_section->vma;
   relocation -= input_section->output_offset;
   relocation -= addr;
+
   if (relocation & 3)
     return bfd_reloc_overflow;
 
   /* Check for overflow */
   if (relocation & 0x02000000)
     {
-      if ((relocation & ~0x03ffffff) != ~0x03ffffff)
+      if ((relocation & ~ (bfd_vma) 0x03ffffff) != ~ (bfd_vma) 0x03ffffff)
        flag = bfd_reloc_overflow;
     }
   else if (relocation & ~0x03ffffff)
@@ -355,272 +641,1911 @@ aoutarm_fix_pcrel_26 (abfd, reloc_entry, symbol, data, input_section,
 
   /* Now the ARM magic... Change the reloc type so that it is marked as done.
      Strictly this is only necessary if we are doing a partial relocation.  */
-  reloc_entry->howto = &aoutarm_std_reloc_howto[7];
-  
-  return flag;
-}
-
-static CONST struct reloc_howto_struct *
-arm_reloc_type_lookup(abfd,code)
-      bfd *abfd;
-      bfd_reloc_code_real_type code;
-{
-#define ASTD(i,j)       case i: return &aoutarm_std_reloc_howto[j]
-  if (code == BFD_RELOC_CTOR)
-    switch (bfd_get_arch_info (abfd)->bits_per_address)
-      {
-      case 32:
-        code = BFD_RELOC_32;
-        break;
-      default: return (CONST struct reloc_howto_struct *) 0;
-      }
+  reloc_entry->howto = &aoutarm_std_reloc_howto[ARM_26D];
 
-  switch (code)
-    {
-      ASTD (BFD_RELOC_16, 1);
-      ASTD (BFD_RELOC_32, 2);
-      ASTD (BFD_RELOC_ARM_PCREL_BRANCH, 3);
-      ASTD (BFD_RELOC_8_PCREL, 4);
-      ASTD (BFD_RELOC_16_PCREL, 5);
-      ASTD (BFD_RELOC_32_PCREL, 6);
-      ASTD (BFD_RELOC_RVA, 11);
-    default: return (CONST struct reloc_howto_struct *) 0;
-    }
+  return flag;
 }
 
-
-#define coff_bfd_reloc_type_lookup arm_reloc_type_lookup
-
-#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2)
-/* The page size is a guess based on ELF.  */
-#define COFF_PAGE_SIZE 0x1000
-
-/* For some reason when using arm COFF the value stored in the .text
-   section for a reference to a common symbol is the value itself plus
-   any desired offset.  Ian Taylor, Cygnus Support.  */
-
-/* If we are producing relocateable output, we need to do some
-   adjustments to the object file that are not done by the
-   bfd_perform_relocation function.  This function is called by every
-   reloc type to make any required adjustments.  */
-
 static bfd_reloc_status_type
-aacoff_arm_reloc (abfd, reloc_entry, symbol, data, input_section, output_bfd,
-                error_message)
+coff_thumb_pcrel_common (abfd, reloc_entry, symbol, data, input_section,
+                    output_bfd, error_message, btype)
      bfd *abfd;
      arelent *reloc_entry;
      asymbol *symbol;
      PTR data;
      asection *input_section;
      bfd *output_bfd;
-     char **error_message;
+     char **error_message ATTRIBUTE_UNUSED;
+     thumb_pcrel_branchtype btype;
 {
-  symvalue diff;
+  bfd_vma relocation = 0;
+  bfd_size_type addr = reloc_entry->address;
+  long target = bfd_get_32 (abfd, (bfd_byte *) data + addr);
+  bfd_reloc_status_type flag = bfd_reloc_ok;
+  bfd_vma dstmsk;
+  bfd_vma offmsk;
+  bfd_vma signbit;
 
-  if (output_bfd == (bfd *) NULL)
-    return bfd_reloc_continue;
+  /* NOTE: This routine is currently used by GAS, but not by the link
+     phase.  */
 
-  if (bfd_is_com_section (symbol->section))
-    {
-      /* We are relocating a common symbol.  The current value in the
-        object file is ORIG + OFFSET, where ORIG is the value of the
-        common symbol as seen by the object file when it was compiled
-        (this may be zero if the symbol was undefined) and OFFSET is
-        the offset into the common symbol (normally zero, but may be
-        non-zero when referring to a field in a common structure).
-        ORIG is the negative of reloc_entry->addend, which is set by
-        the CALC_ADDEND macro below.  We want to replace the value in
-        the object file with NEW + OFFSET, where NEW is the value of
-        the common symbol which we are going to put in the final
-        object file.  NEW is symbol->value.  */
-      diff = symbol->value + reloc_entry->addend;
-    }
-  else
+  switch (btype)
     {
-      /* For some reason bfd_perform_relocation always effectively
-        ignores the addend for a COFF target when producing
-        relocateable output.  This seems to be always wrong for arm
-        COFF, so we handle the addend here instead.  */
-      diff = reloc_entry->addend;
+    case b9:
+      dstmsk  = 0x000000ff;
+      offmsk  = 0x000001fe;
+      signbit = 0x00000100;
+      break;
+
+    case b12:
+      dstmsk  = 0x000007ff;
+      offmsk  = 0x00000ffe;
+      signbit = 0x00000800;
+      break;
+
+    case b23:
+      dstmsk  = 0x07ff07ff;
+      offmsk  = 0x007fffff;
+      signbit = 0x00400000;
+      break;
+
+    default:
+      abort ();
     }
 
-#define DOIT(x) \
-  x = ((x & ~howto->dst_mask) | (((x & howto->src_mask) + diff) & howto->dst_mask))
+  /* If this is an undefined symbol, return error */
+  if (symbol->section == &bfd_und_section
+      && (symbol->flags & BSF_WEAK) == 0)
+    return output_bfd ? bfd_reloc_continue : bfd_reloc_undefined;
 
-  if (diff != 0)
-    {
-      reloc_howto_type *howto = reloc_entry->howto;
-      unsigned char *addr = (unsigned char *) data + reloc_entry->address;
+  /* If the sections are different, and we are doing a partial relocation,
+     just ignore it for now.  */
+  if (symbol->section->name != input_section->name
+      && output_bfd != (bfd *)NULL)
+    return bfd_reloc_continue;
 
-      switch (howto->size)
-       {
-       case 0:
-         {
-           char x = bfd_get_8 (abfd, addr);
-           DOIT (x);
-           bfd_put_8 (abfd, x, addr);
-         }
-         break;
+  switch (btype)
+    {
+    case b9:
+    case b12:
+      relocation = ((target & dstmsk) << 1);
+      break;
+
+    case b23:
+      if (bfd_big_endian (abfd))
+       relocation = ((target & 0x7ff) << 1)  | ((target & 0x07ff0000) >> 4);
+      else
+       relocation = ((target & 0x7ff) << 12) | ((target & 0x07ff0000) >> 15);
+      break;
+
+    default:
+      abort ();
+    }
 
-       case 1:
-         {
-           short x = bfd_get_16 (abfd, addr);
-           DOIT (x);
-           bfd_put_16 (abfd, x, addr);
-         }
-         break;
+  relocation = (relocation ^ signbit) - signbit; /* Sign extend */
+  relocation += symbol->value;
+  relocation += symbol->section->output_section->vma;
+  relocation += symbol->section->output_offset;
+  relocation += reloc_entry->addend;
+  relocation -= input_section->output_section->vma;
+  relocation -= input_section->output_offset;
+  relocation -= addr;
 
-       case 2:
-         {
-           long x = bfd_get_32 (abfd, addr);
-           DOIT (x);
-           bfd_put_32 (abfd, x, addr);
-         }
-         break;
+  if (relocation & 1)
+    return bfd_reloc_overflow;
 
-       default:
-         abort ();
-       }
+  /* Check for overflow */
+  if (relocation & signbit)
+    {
+      if ((relocation & ~offmsk) != ~offmsk)
+       flag = bfd_reloc_overflow;
     }
+  else if (relocation & ~offmsk)
+    flag = bfd_reloc_overflow;
 
-  /* Now let bfd_perform_relocation finish everything up.  */
-  return bfd_reloc_continue;
-}
-
+  target &= ~dstmsk;
+  switch (btype)
+   {
+   case b9:
+   case b12:
+     target |= (relocation >> 1);
+     break;
+
+   case b23:
+     if (bfd_big_endian (abfd))
+       target |= ((relocation & 0xfff) >> 1)  | ((relocation << 4)  & 0x07ff0000);
+     else
+       target |= ((relocation & 0xffe) << 15) | ((relocation >> 12) & 0x7ff);
+     break;
+
+   default:
+     abort ();
+   }
 
+  bfd_put_32 (abfd, target, (bfd_byte *) data + addr);
 
+  /* Now the ARM magic... Change the reloc type so that it is marked as done.
+     Strictly this is only necessary if we are doing a partial relocation.  */
+  reloc_entry->howto = & aoutarm_std_reloc_howto [ARM_26D];
 
+  /* TODO: We should possibly have DONE entries for the THUMB PCREL relocations */
+  return flag;
+}
 
+static bfd_reloc_status_type
+coff_thumb_pcrel_23 (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;
+{
+  return coff_thumb_pcrel_common (abfd, reloc_entry, symbol, data,
+                                  input_section, output_bfd, error_message, b23);
+}
+
+static bfd_reloc_status_type
+coff_thumb_pcrel_12 (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;
+{
+  return coff_thumb_pcrel_common (abfd, reloc_entry, symbol, data,
+                                  input_section, output_bfd, error_message, b12);
+}
+
+static bfd_reloc_status_type
+coff_thumb_pcrel_9 (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;
+{
+  return coff_thumb_pcrel_common (abfd, reloc_entry, symbol, data,
+                                  input_section, output_bfd, error_message, b9);
+}
+
+static CONST struct reloc_howto_struct *
+coff_arm_reloc_type_lookup (abfd, code)
+      bfd * abfd;
+      bfd_reloc_code_real_type code;
+{
+#define ASTD(i,j)       case i: return aoutarm_std_reloc_howto + j
+
+  if (code == BFD_RELOC_CTOR)
+    switch (bfd_get_arch_info (abfd)->bits_per_address)
+      {
+      case 32:
+        code = BFD_RELOC_32;
+        break;
+      default: return (CONST struct reloc_howto_struct *) 0;
+      }
+
+  switch (code)
+    {
+#ifdef ARM_WINCE
+      ASTD (BFD_RELOC_32,                   ARM_32);
+      ASTD (BFD_RELOC_RVA,                  ARM_RVA32);
+      ASTD (BFD_RELOC_ARM_PCREL_BRANCH,     ARM_26);
+      ASTD (BFD_RELOC_THUMB_PCREL_BRANCH12, ARM_THUMB12);
+#else
+      ASTD (BFD_RELOC_8,                    ARM_8);
+      ASTD (BFD_RELOC_16,                   ARM_16);
+      ASTD (BFD_RELOC_32,                   ARM_32);
+      ASTD (BFD_RELOC_ARM_PCREL_BRANCH,     ARM_26);
+      ASTD (BFD_RELOC_ARM_PCREL_BLX,        ARM_26);
+      ASTD (BFD_RELOC_8_PCREL,              ARM_DISP8);
+      ASTD (BFD_RELOC_16_PCREL,             ARM_DISP16);
+      ASTD (BFD_RELOC_32_PCREL,             ARM_DISP32);
+      ASTD (BFD_RELOC_RVA,                  ARM_RVA32);
+      ASTD (BFD_RELOC_THUMB_PCREL_BRANCH9,  ARM_THUMB9);
+      ASTD (BFD_RELOC_THUMB_PCREL_BRANCH12, ARM_THUMB12);
+      ASTD (BFD_RELOC_THUMB_PCREL_BRANCH23, ARM_THUMB23);
+#endif
+    default: return (CONST struct reloc_howto_struct *) 0;
+    }
+}
+
+#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2)
+#define COFF_PAGE_SIZE 0x1000
 /* Turn a howto into a reloc  nunmber */
 
 #define SELECT_RELOC(x,howto) { x.r_type = howto->type; }
 #define BADMAG(x) ARMBADMAG(x)
 #define ARM 1                  /* Customize coffcode.h */
 
+/* Extend the coff_link_hash_table structure with a few ARM specific fields.
+   This allows us to store global data here without actually creating any
+   global variables, which is a no-no in the BFD world.  */
+struct coff_arm_link_hash_table
+{
+  /* The original coff_link_hash_table structure.  MUST be first field.  */
+  struct coff_link_hash_table  root;
 
-/* On SCO Unix 3.2.2 the native assembler generates two .data
-   sections.  We handle that by renaming the second one to .data2.  It
-   does no harm to do this for any arm COFF target.  */
-#define TWO_DATA_SECS
+  /* The size in bytes of the section containg the Thumb-to-ARM glue.  */
+  long int                     thumb_glue_size;
 
-/* For arm COFF a STYP_NOLOAD | STYP_BSS section is part of a shared
-   library.  On some other COFF targets STYP_BSS is normally
-   STYP_NOLOAD.  */
-#define BSS_NOLOAD_IS_SHARED_LIBRARY
+  /* The size in bytes of the section containg the ARM-to-Thumb glue.  */
+  long int                     arm_glue_size;
 
+  /* An arbitary input BFD chosen to hold the glue sections.  */
+  bfd *                                bfd_of_glue_owner;
 
-/* We use the special COFF backend linker.  */
-#define coff_relocate_section _bfd_coff_generic_relocate_section
+  /* Support interworking with old, non-interworking aware ARM code.  */
+  int                          support_old_code;
+};
 
+/* Get the ARM coff linker hash table from a link_info structure.  */
+#define coff_arm_hash_table(info) \
+  ((struct coff_arm_link_hash_table *) ((info)->hash))
 
+/* Create an ARM coff linker hash table.  */
 
-#include "coffcode.h"
+static struct bfd_link_hash_table *
+coff_arm_link_hash_table_create (abfd)
+     bfd * abfd;
+{
+  struct coff_arm_link_hash_table * ret;
+
+  ret = ((struct coff_arm_link_hash_table *)
+        bfd_alloc (abfd, sizeof (struct coff_arm_link_hash_table)));
+  if (ret == (struct coff_arm_link_hash_table *) NULL)
+    return NULL;
+
+  if (! _bfd_coff_link_hash_table_init
+      (& ret->root, abfd, _bfd_coff_link_hash_newfunc))
+    {
+      bfd_release (abfd, ret);
+      return (struct bfd_link_hash_table *) NULL;
+    }
+
+  ret->thumb_glue_size   = 0;
+  ret->arm_glue_size     = 0;
+  ret->bfd_of_glue_owner = NULL;
 
-static const bfd_target *
-i3coff_object_p(a)
-     bfd *a;
+  return & ret->root.root;
+}
+
+static void
+arm_emit_base_file_entry (info, output_bfd, input_section, reloc_offset)
+      struct bfd_link_info *info;
+      bfd *output_bfd;
+      asection *input_section;
+      bfd_vma reloc_offset;
 {
-  return coff_object_p(a);
+  bfd_vma addr = reloc_offset
+                - input_section->vma
+                + input_section->output_offset
+                  + input_section->output_section->vma;
+
+  if (coff_data(output_bfd)->pe)
+     addr -= pe_data(output_bfd)->pe_opthdr.ImageBase;
+  fwrite (&addr, 1, sizeof (addr), (FILE *) info->base_file);
+
+}
+\f
+/* The thumb form of a long branch is a bit finicky, because the offset
+   encoding is split over two fields, each in it's own instruction. They
+   can occur in any order. So given a thumb form of long branch, and an
+   offset, insert the offset into the thumb branch and return finished
+   instruction.
+
+   It takes two thumb instructions to encode the target address. Each has
+   11 bits to invest. The upper 11 bits are stored in one (identifed by
+   H-0.. see below), the lower 11 bits are stored in the other (identified
+   by H-1).
+
+   Combine together and shifted left by 1 (it's a half word address) and
+   there you have it.
+
+     Op: 1111 = F,
+     H-0, upper address-0 = 000
+     Op: 1111 = F,
+     H-1, lower address-0 = 800
+
+   They can be ordered either way, but the arm tools I've seen always put
+   the lower one first. It probably doesn't matter. krk@cygnus.com
+
+   XXX:  Actually the order does matter.  The second instruction (H-1)
+   moves the computed address into the PC, so it must be the second one
+   in the sequence.  The problem, however is that whilst little endian code
+   stores the instructions in HI then LOW order, big endian code does the
+   reverse.  nickc@cygnus.com  */
+
+#define LOW_HI_ORDER 0xF800F000
+#define HI_LOW_ORDER 0xF000F800
+
+static insn32
+insert_thumb_branch (br_insn, rel_off)
+     insn32 br_insn;
+     int rel_off;
+{
+  unsigned int low_bits;
+  unsigned int high_bits;
+
+  BFD_ASSERT((rel_off & 1) != 1);
+
+  rel_off >>= 1;                              /* half word aligned address */
+  low_bits = rel_off & 0x000007FF;            /* the bottom 11 bits */
+  high_bits = (rel_off >> 11) & 0x000007FF;   /* the top 11 bits */
+
+  if ((br_insn & LOW_HI_ORDER) == LOW_HI_ORDER)
+    br_insn = LOW_HI_ORDER | (low_bits << 16) | high_bits;
+  else if ((br_insn & HI_LOW_ORDER) == HI_LOW_ORDER)
+    br_insn = HI_LOW_ORDER | (high_bits << 16) | low_bits;
+  else
+    abort (); /* error - not a valid branch instruction form */
+
+  /* FIXME: abort is probably not the right call. krk@cygnus.com */
+
+  return br_insn;
 }
 
-#ifdef TARGET_LITTLE_SYM
-const bfd_target TARGET_LITTLE_SYM =
+\f
+static struct coff_link_hash_entry *
+find_thumb_glue (info, name, input_bfd)
+     struct bfd_link_info * info;
+     CONST char *           name;
+     bfd *                  input_bfd;
 {
-  TARGET_LITTLE_NAME,          /* name or coff-arm-little */
-  bfd_target_coff_flavour,
-  false,                       /* data byte order is little */
-  false,                       /* header byte order is little */
-
-  (HAS_RELOC | EXEC_P |                /* object flags */
-   HAS_LINENO | HAS_DEBUG |
-   HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
-
-  (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
-#ifdef TARGET_UNDERSCORE
-  TARGET_UNDERSCORE,           /* leading underscore */
-#else
-  0,                           /* leading underscore */
+  char *                        tmp_name;
+  struct coff_link_hash_entry * myh;
+
+  tmp_name = ((char *)
+        bfd_malloc (strlen (name) + strlen (THUMB2ARM_GLUE_ENTRY_NAME) + 1));
+
+  BFD_ASSERT (tmp_name);
+
+  sprintf (tmp_name, THUMB2ARM_GLUE_ENTRY_NAME, name);
+
+  myh = coff_link_hash_lookup
+    (coff_hash_table (info), tmp_name, false, false, true);
+
+  if (myh == NULL)
+    /* xgettext:c-format */
+    _bfd_error_handler (_("%s: unable to find THUMB glue '%s' for `%s'"),
+                       bfd_get_filename (input_bfd), tmp_name, name);
+
+  free (tmp_name);
+
+  return myh;
+}
+
+static struct coff_link_hash_entry *
+find_arm_glue (info, name, input_bfd)
+     struct bfd_link_info * info;
+     CONST char *           name;
+     bfd *                  input_bfd;
+{
+  char *                        tmp_name;
+  struct coff_link_hash_entry * myh;
+
+  tmp_name = ((char *)
+             bfd_malloc (strlen (name) + strlen (ARM2THUMB_GLUE_ENTRY_NAME) + 1));
+
+  BFD_ASSERT (tmp_name);
+
+  sprintf (tmp_name, ARM2THUMB_GLUE_ENTRY_NAME, name);
+
+  myh = coff_link_hash_lookup
+    (coff_hash_table (info), tmp_name, false, false, true);
+
+  if (myh == NULL)
+    /* xgettext:c-format */
+    _bfd_error_handler (_("%s: unable to find ARM glue '%s' for `%s'"),
+                       bfd_get_filename (input_bfd), tmp_name, name);
+
+  free (tmp_name);
+
+  return myh;
+}
+
+/*
+  ARM->Thumb glue:
+
+       .arm
+       __func_from_arm:
+            ldr r12, __func_addr
+            bx  r12
+       __func_addr:
+            .word func    @ behave as if you saw a ARM_32 reloc
+*/
+
+#define ARM2THUMB_GLUE_SIZE 12
+static const insn32 a2t1_ldr_insn       = 0xe59fc000;
+static const insn32 a2t2_bx_r12_insn    = 0xe12fff1c;
+static const insn32 a2t3_func_addr_insn = 0x00000001;
+
+/*
+   Thumb->ARM:                         Thumb->(non-interworking aware) ARM
+
+   .thumb                              .thumb
+   .align 2                            .align 2
+      __func_from_thumb:                  __func_from_thumb:
+          bx pc                                push {r6, lr}
+          nop                                  ldr  r6, __func_addr
+   .arm                                                mov  lr, pc
+      __func_change_to_arm:                    bx   r6
+          b func                       .arm
+                                          __func_back_to_thumb:
+                                               ldmia r13! {r6, lr}
+                                               bx    lr
+                                          __func_addr:
+                                               .word   func
+*/
+
+#define THUMB2ARM_GLUE_SIZE (globals->support_old_code ? 20 : 8)
+static const insn16 t2a1_bx_pc_insn = 0x4778;
+static const insn16 t2a2_noop_insn  = 0x46c0;
+static const insn32 t2a3_b_insn     = 0xea000000;
+
+static const insn16 t2a1_push_insn  = 0xb540;
+static const insn16 t2a2_ldr_insn   = 0x4e03;
+static const insn16 t2a3_mov_insn   = 0x46fe;
+static const insn16 t2a4_bx_insn    = 0x4730;
+static const insn32 t2a5_pop_insn   = 0xe8bd4040;
+static const insn32 t2a6_bx_insn    = 0xe12fff1e;
+
+/* TODO:
+     We should really create new local (static) symbols in destination
+     object for each stub we create.  We should also create local
+     (static) symbols within the stubs when switching between ARM and
+     Thumb code.  This will ensure that the debugger and disassembler
+     can present a better view of stubs.
+
+     We can treat stubs like literal sections, and for the THUMB9 ones
+     (short addressing range) we should be able to insert the stubs
+     between sections. i.e. the simplest approach (since relocations
+     are done on a section basis) is to dump the stubs at the end of
+     processing a section. That way we can always try and minimise the
+     offset to and from a stub. However, this does not map well onto
+     the way that the linker/BFD does its work: mapping all input
+     sections to output sections via the linker script before doing
+     all the processing.
+
+     Unfortunately it may be easier to just to disallow short range
+     Thumb->ARM stubs (i.e. no conditional inter-working branches,
+     only branch-and-link (BL) calls.  This will simplify the processing
+     since we can then put all of the stubs into their own section.
+
+  TODO:
+     On a different subject, rather than complaining when a
+     branch cannot fit in the number of bits available for the
+     instruction we should generate a trampoline stub (needed to
+     address the complete 32bit address space).  */
+
+/* The standard COFF backend linker does not cope with the special
+   Thumb BRANCH23 relocation.  The alternative would be to split the
+   BRANCH23 into seperate HI23 and LO23 relocations. However, it is a
+   bit simpler simply providing our own relocation driver.  */
+
+/* The reloc processing routine for the ARM/Thumb COFF linker.  NOTE:
+   This code is a very slightly modified copy of
+   _bfd_coff_generic_relocate_section.  It would be a much more
+   maintainable solution to have a MACRO that could be expanded within
+   _bfd_coff_generic_relocate_section that would only be provided for
+   ARM/Thumb builds.  It is only the code marked THUMBEXTENSION that
+   is different from the original.  */
+
+static boolean
+coff_arm_relocate_section (output_bfd, info, input_bfd, input_section,
+                           contents, relocs, syms, sections)
+     bfd *output_bfd;
+     struct bfd_link_info *info;
+     bfd *input_bfd;
+     asection *input_section;
+     bfd_byte *contents;
+     struct internal_reloc *relocs;
+     struct internal_syment *syms;
+     asection **sections;
+{
+  struct internal_reloc * rel;
+  struct internal_reloc * relend;
+
+  rel = relocs;
+  relend = rel + input_section->reloc_count;
+
+  for (; rel < relend; rel++)
+    {
+      int                            done = 0;
+      long                           symndx;
+      struct coff_link_hash_entry *  h;
+      struct internal_syment *       sym;
+      bfd_vma                        addend;
+      bfd_vma                        val;
+      reloc_howto_type *             howto;
+      bfd_reloc_status_type          rstat;
+      bfd_vma                        h_val;
+
+      symndx = rel->r_symndx;
+
+      if (symndx == -1)
+       {
+         h = NULL;
+         sym = NULL;
+       }
+      else
+       {
+         h = obj_coff_sym_hashes (input_bfd)[symndx];
+         sym = syms + symndx;
+       }
+
+      /* COFF treats common symbols in one of two ways.  Either the
+         size of the symbol is included in the section contents, or it
+         is not.  We assume that the size is not included, and force
+         the rtype_to_howto function to adjust the addend as needed.  */
+
+      if (sym != NULL && sym->n_scnum != 0)
+       addend = - sym->n_value;
+      else
+       addend = 0;
+
+      howto = coff_rtype_to_howto (input_bfd, input_section, rel, h,
+                                      sym, &addend);
+      if (howto == NULL)
+       return false;
+
+      /* The relocation_section function will skip pcrel_offset relocs
+         when doing a relocateable link.  However, we want to convert
+         ARM26 to ARM26D relocs if possible.  We return a fake howto in
+         this case without pcrel_offset set, and adjust the addend to
+         compensate.  */
+      if (rel->r_type == ARM_26
+          && h != NULL
+          && info->relocateable
+          && (h->root.type == bfd_link_hash_defined
+             || h->root.type == bfd_link_hash_defweak)
+          && h->root.u.def.section->output_section == input_section->output_section)
+        {
+          static reloc_howto_type fake_arm26_reloc =
+           HOWTO (ARM_26,
+              2,
+              2,
+              24,
+              true,
+              0,
+              complain_overflow_signed,
+              aoutarm_fix_pcrel_26 ,
+              "ARM_26",
+              false,
+              0x00ffffff,
+              0x00ffffff,
+              false);
+
+          addend -= rel->r_vaddr - input_section->vma;
+          howto = &fake_arm26_reloc;
+        }
+
+#ifdef ARM_WINCE
+      /* MS ARM-CE makes the reloc relative to the opcode's pc, not
+        the next opcode's pc, so is off by one.  */
+      if (howto->pc_relative && !info->relocateable)
+       addend -= 8;
 #endif
-  '/',                         /* ar_pad_char */
-  15,                          /* ar_max_namelen */
-
-  2,                           /* minimum alignment power */
-  bfd_getl64, bfd_getl_signed_64, bfd_putl64,
-     bfd_getl32, bfd_getl_signed_32, bfd_putl32,
-     bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */
-  bfd_getl64, bfd_getl_signed_64, bfd_putl64,
-     bfd_getl32, bfd_getl_signed_32, bfd_putl32,
-     bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */
-
-/* Note that we allow an object file to be treated as a core file as well. */
-    {_bfd_dummy_target, i3coff_object_p, /* bfd_check_format */
-       bfd_generic_archive_p, i3coff_object_p},
-    {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */
-       bfd_false},
-    {bfd_false, coff_write_object_contents, /* bfd_write_contents */
-       _bfd_write_archive_contents, bfd_false},
-
-     BFD_JUMP_TABLE_GENERIC (coff),
-     BFD_JUMP_TABLE_COPY (coff),
-     BFD_JUMP_TABLE_CORE (_bfd_nocore),
-     BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff),
-     BFD_JUMP_TABLE_SYMBOLS (coff),
-     BFD_JUMP_TABLE_RELOCS (coff),
-     BFD_JUMP_TABLE_WRITE (coff),
-     BFD_JUMP_TABLE_LINK (coff),
-     BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
-
-  COFF_SWAP_TABLE,
-};
+
+      /* If we are doing a relocateable link, then we can just ignore
+         a PC relative reloc that is pcrel_offset.  It will already
+         have the correct value.  If this is not a relocateable link,
+         then we should ignore the symbol value.  */
+      if (howto->pc_relative && howto->pcrel_offset)
+        {
+          if (info->relocateable)
+            continue;
+#if 0  /* We must not ignore the symbol value.  If the symbol is
+         within the same section, the relocation should have already
+         been fixed, but if it is not, we'll be handed a reloc into
+         the beginning of the symbol's section, so we must not cancel
+         out the symbol's value, otherwise we'll be adding it in
+         twice.  */
+          if (sym != NULL && sym->n_scnum != 0)
+            addend += sym->n_value;
 #endif
+        }
+
+      val = 0;
 
-#ifdef TARGET_BIG_SYM
-const bfd_target TARGET_BIG_SYM =
+      if (h == NULL)
+       {
+         asection *sec;
+
+         if (symndx == -1)
+           {
+             sec = bfd_abs_section_ptr;
+             val = 0;
+           }
+         else
+           {
+             sec = sections[symndx];
+              val = (sec->output_section->vma
+                    + sec->output_offset
+                    + sym->n_value
+                    - sec->vma);
+           }
+       }
+      else
+       {
+#if 1 /* THUMBEXTENSION */
+          /* We don't output the stubs if we are generating a
+             relocatable output file, since we may as well leave the
+             stub generation to the final linker pass. If we fail to
+            verify that the name is defined, we'll try to build stubs
+            for an undefined name...  */
+          if (! info->relocateable
+             && (   h->root.type == bfd_link_hash_defined
+                 || h->root.type == bfd_link_hash_defweak))
+            {
+             asection *   h_sec = h->root.u.def.section;
+             const char * name  = h->root.root.string;
+
+             /* h locates the symbol referenced in the reloc.  */
+             h_val = (h->root.u.def.value
+                      + h_sec->output_section->vma
+                      + h_sec->output_offset);
+
+              if (howto->type == ARM_26)
+                {
+                  if (   h->class == C_THUMBSTATFUNC
+                     || h->class == C_THUMBEXTFUNC)
+                   {
+                     /* Arm code calling a Thumb function */
+                     unsigned long int                 tmp;
+                     long int                          my_offset;
+                     asection *                        s;
+                     long int                          ret_offset;
+                     struct coff_link_hash_entry *     myh;
+                     struct coff_arm_link_hash_table * globals;
+
+                     myh = find_arm_glue (info, name, input_bfd);
+                     if (myh == NULL)
+                       return false;
+
+                     globals = coff_arm_hash_table (info);
+
+                     BFD_ASSERT (globals != NULL);
+                     BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
+
+                     my_offset = myh->root.u.def.value;
+
+                     s = bfd_get_section_by_name (globals->bfd_of_glue_owner,
+                                                 ARM2THUMB_GLUE_SECTION_NAME);
+                     BFD_ASSERT (s != NULL);
+                     BFD_ASSERT (s->contents != NULL);
+                     BFD_ASSERT (s->output_section != NULL);
+
+                     if ((my_offset & 0x01) == 0x01)
+                       {
+                         if (h_sec->owner != NULL
+                             && INTERWORK_SET (h_sec->owner)
+                             && ! INTERWORK_FLAG (h_sec->owner))
+                           {
+                             _bfd_error_handler
+                               /* xgettext:c-format */
+                               (_("%s(%s): warning: interworking not enabled."),
+                                bfd_get_filename (h_sec->owner), name);
+                             _bfd_error_handler
+                               /* xgettext:c-format */
+                               (_("  first occurrence: %s: arm call to thumb"),
+                                bfd_get_filename (input_bfd));
+                           }
+
+                         --my_offset;
+                         myh->root.u.def.value = my_offset;
+
+                         bfd_put_32 (output_bfd, a2t1_ldr_insn,
+                                     s->contents + my_offset);
+
+                         bfd_put_32 (output_bfd, a2t2_bx_r12_insn,
+                                     s->contents + my_offset + 4);
+
+                         /* It's a thumb address.  Add the low order bit.  */
+                         bfd_put_32 (output_bfd, h_val | a2t3_func_addr_insn,
+                                     s->contents + my_offset + 8);
+
+                          if (info->base_file)
+                            arm_emit_base_file_entry (info, output_bfd, s,
+                                                            my_offset + 8);
+
+                       }
+
+                     BFD_ASSERT (my_offset <= globals->arm_glue_size);
+
+                     tmp = bfd_get_32 (input_bfd, contents + rel->r_vaddr
+                                       - input_section->vma);
+
+                     tmp = tmp & 0xFF000000;
+
+                     /* Somehow these are both 4 too far, so subtract 8.  */
+                     ret_offset =
+                       s->output_offset
+                       + my_offset
+                       + s->output_section->vma
+                       - (input_section->output_offset
+                          + input_section->output_section->vma
+                          + rel->r_vaddr)
+                       - 8;
+
+                     tmp = tmp | ((ret_offset >> 2) & 0x00FFFFFF);
+
+                     bfd_put_32 (output_bfd, tmp, contents + rel->r_vaddr
+                                 - input_section->vma);
+                     done = 1;
+                   }
+                }
+
+#ifndef ARM_WINCE
+             /* Note: We used to check for ARM_THUMB9 and ARM_THUMB12 */
+              else if (howto->type == ARM_THUMB23)
+                {
+                  if (   h->class == C_EXT
+                     || h->class == C_STAT
+                     || h->class == C_LABEL)
+                   {
+                     /* Thumb code calling an ARM function */
+                     asection *                         s = 0;
+                     long int                           my_offset;
+                     unsigned long int                  tmp;
+                     long int                           ret_offset;
+                     struct coff_link_hash_entry *      myh;
+                     struct coff_arm_link_hash_table *  globals;
+
+                     myh = find_thumb_glue (info, name, input_bfd);
+                     if (myh == NULL)
+                       return false;
+
+                     globals = coff_arm_hash_table (info);
+
+                     BFD_ASSERT (globals != NULL);
+                     BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
+
+                     my_offset = myh->root.u.def.value;
+
+                     s = bfd_get_section_by_name (globals->bfd_of_glue_owner,
+                                                  THUMB2ARM_GLUE_SECTION_NAME);
+
+                     BFD_ASSERT (s != NULL);
+                     BFD_ASSERT (s->contents != NULL);
+                     BFD_ASSERT (s->output_section != NULL);
+
+                     if ((my_offset & 0x01) == 0x01)
+                       {
+                         if (h_sec->owner != NULL
+                             && INTERWORK_SET (h_sec->owner)
+                             && ! INTERWORK_FLAG (h_sec->owner)
+                             && ! globals->support_old_code)
+                           {
+                             _bfd_error_handler
+                               /* xgettext:c-format */
+                               (_("%s(%s): warning: interworking not enabled."),
+                                bfd_get_filename (h_sec->owner), name);
+                             _bfd_error_handler
+                               /* xgettext:c-format */
+                               (_("  first occurrence: %s: thumb call to arm"),
+                                bfd_get_filename (input_bfd));
+                             _bfd_error_handler
+                               (_("  consider relinking with --support-old-code enabled"));
+                           }
+
+                         -- my_offset;
+                         myh->root.u.def.value = my_offset;
+
+                         if (globals->support_old_code)
+                           {
+                             bfd_put_16 (output_bfd, t2a1_push_insn,
+                                         s->contents + my_offset);
+
+                             bfd_put_16 (output_bfd, t2a2_ldr_insn,
+                                         s->contents + my_offset + 2);
+
+                             bfd_put_16 (output_bfd, t2a3_mov_insn,
+                                         s->contents + my_offset + 4);
+
+                             bfd_put_16 (output_bfd, t2a4_bx_insn,
+                                         s->contents + my_offset + 6);
+
+                             bfd_put_32 (output_bfd, t2a5_pop_insn,
+                                         s->contents + my_offset + 8);
+
+                             bfd_put_32 (output_bfd, t2a6_bx_insn,
+                                         s->contents + my_offset + 12);
+
+                             /* Store the address of the function in the last word of the stub.  */
+                             bfd_put_32 (output_bfd, h_val,
+                                         s->contents + my_offset + 16);
+
+                              if (info->base_file)
+                                arm_emit_base_file_entry (info, output_bfd, s, my_offset + 16);
+                           }
+                         else
+                           {
+                             bfd_put_16 (output_bfd, t2a1_bx_pc_insn,
+                                         s->contents + my_offset);
+
+                             bfd_put_16 (output_bfd, t2a2_noop_insn,
+                                         s->contents + my_offset + 2);
+
+                             ret_offset =
+                               ((bfd_signed_vma) h_val)        /* Address of destination of the stub */
+                               - ((bfd_signed_vma)
+                                  (s->output_offset            /* Offset from the start of the current section to the start of the stubs.  */
+                                   + my_offset                 /* Offset of the start of this stub from the start of the stubs.  */
+                                   + s->output_section->vma)   /* Address of the start of the current section.  */
+                                  + 4                          /* The branch instruction is 4 bytes into the stub.  */
+                                  + 8);                        /* ARM branches work from the pc of the instruction + 8.  */
+
+                             bfd_put_32 (output_bfd,
+                                         t2a3_b_insn | ((ret_offset >> 2) & 0x00FFFFFF),
+                                         s->contents + my_offset + 4);
+
+                           }
+                       }
+
+                     BFD_ASSERT (my_offset <= globals->thumb_glue_size);
+
+                     /* Now go back and fix up the original BL insn to point
+                        to here.  */
+                     ret_offset =
+                       s->output_offset
+                       + my_offset
+                       - (input_section->output_offset
+                          + rel->r_vaddr)
+                       -4;
+
+                     tmp = bfd_get_32 (input_bfd, contents + rel->r_vaddr
+                                       - input_section->vma);
+
+                     bfd_put_32 (output_bfd,
+                                 insert_thumb_branch (tmp, ret_offset),
+                                 contents + rel->r_vaddr
+                                 - input_section->vma);
+
+                     done = 1;
+                    }
+                }
+#endif
+            }
+
+          /* If the relocation type and destination symbol does not
+             fall into one of the above categories, then we can just
+             perform a direct link.  */
+
+         if (done)
+           rstat = bfd_reloc_ok;
+         else
+#endif /* THUMBEXTENSION */
+           if (   h->root.type == bfd_link_hash_defined
+               || h->root.type == bfd_link_hash_defweak)
+           {
+             asection *sec;
+
+             sec = h->root.u.def.section;
+             val = (h->root.u.def.value
+                    + sec->output_section->vma
+                    + sec->output_offset);
+             }
+
+         else if (! info->relocateable)
+           {
+             if (! ((*info->callbacks->undefined_symbol)
+                    (info, h->root.root.string, input_bfd, input_section,
+                     rel->r_vaddr - input_section->vma, true)))
+               return false;
+           }
+       }
+
+      if (info->base_file)
+       {
+         /* Emit a reloc if the backend thinks it needs it.  */
+         if (sym && pe_data(output_bfd)->in_reloc_p(output_bfd, howto))
+            arm_emit_base_file_entry (info, output_bfd, input_section, rel->r_vaddr);
+       }
+
+#if 1 /* THUMBEXTENSION */
+      if (done)
+       rstat = bfd_reloc_ok;
+#ifndef ARM_WINCE
+      /* Only perform this fix during the final link, not a relocatable link.  nickc@cygnus.com  */
+      else if (! info->relocateable
+              && howto->type == ARM_THUMB23)
+        {
+          /* This is pretty much a copy of what the default
+             _bfd_final_link_relocate and _bfd_relocate_contents
+             routines do to perform a relocation, with special
+             processing for the split addressing of the Thumb BL
+             instruction.  Again, it would probably be simpler adding a
+             ThumbBRANCH23 specific macro expansion into the default
+             code.  */
+
+          bfd_vma address = rel->r_vaddr - input_section->vma;
+
+          if (address > input_section->_raw_size)
+           rstat = bfd_reloc_outofrange;
+          else
+            {
+              bfd_vma         relocation       = val + addend;
+             int             size             = bfd_get_reloc_size (howto);
+             boolean         overflow         = false;
+             bfd_byte *      location         = contents + address;
+             bfd_vma         x                = bfd_get_32 (input_bfd, location);
+             bfd_vma         src_mask         = 0x007FFFFE;
+             bfd_signed_vma  reloc_signed_max = (1 << (howto->bitsize - 1)) - 1;
+             bfd_signed_vma  reloc_signed_min = ~reloc_signed_max;
+             bfd_vma         check;
+             bfd_signed_vma  signed_check;
+             bfd_vma         add;
+             bfd_signed_vma  signed_add;
+
+             BFD_ASSERT (size == 4);
+
+              /* howto->pc_relative should be TRUE for type 14 BRANCH23 */
+              relocation -= (input_section->output_section->vma
+                             + input_section->output_offset);
+
+              /* howto->pcrel_offset should be TRUE for type 14 BRANCH23 */
+              relocation -= address;
+
+             /* No need to negate the relocation with BRANCH23.  */
+             /* howto->complain_on_overflow == complain_overflow_signed for BRANCH23.  */
+             /* howto->rightshift == 1 */
+             /* Drop unwanted bits from the value we are relocating to.  */
+
+             check = relocation >> howto->rightshift;
+
+             /* If this is a signed value, the rightshift just dropped
+                leading 1 bits (assuming twos complement).  */
+             if ((bfd_signed_vma) relocation >= 0)
+               signed_check = check;
+             else
+               signed_check = (check
+                               | ((bfd_vma) - 1
+                                  & ~((bfd_vma) - 1 >> howto->rightshift)));
+
+             /* Get the value from the object file.  */
+             if (bfd_big_endian (input_bfd))
+               {
+                 add = (((x) & 0x07ff0000) >> 4) | (((x) & 0x7ff) << 1);
+               }
+             else
+               {
+                 add = ((((x) & 0x7ff) << 12) | (((x) & 0x07ff0000) >> 15));
+               }
+
+             /* Get the value from the object file with an appropriate sign.
+                The expression involving howto->src_mask isolates the upper
+                bit of src_mask.  If that bit is set in the value we are
+                adding, it is negative, and we subtract out that number times
+                two.  If src_mask includes the highest possible bit, then we
+                can not get the upper bit, but that does not matter since
+                signed_add needs no adjustment to become negative in that
+                case.  */
+
+             signed_add = add;
+
+             if ((add & (((~ src_mask) >> 1) & src_mask)) != 0)
+               signed_add -= (((~ src_mask) >> 1) & src_mask) << 1;
+
+             /* Add the value from the object file, shifted so that it is a
+                straight number.  */
+             /* howto->bitpos == 0 */
+
+             signed_check += signed_add;
+             relocation += signed_add;
+
+             BFD_ASSERT (howto->complain_on_overflow == complain_overflow_signed);
+
+             /* Assumes two's complement.  */
+             if (   signed_check > reloc_signed_max
+                 || signed_check < reloc_signed_min)
+               overflow = true;
+
+             /* Put RELOCATION into the correct bits:  */
+
+             if (bfd_big_endian (input_bfd))
+               {
+                 relocation = (((relocation & 0xffe) >> 1)  | ((relocation << 4) & 0x07ff0000));
+               }
+             else
+               {
+                 relocation = (((relocation & 0xffe) << 15) | ((relocation >> 12) & 0x7ff));
+               }
+
+             /* Add RELOCATION to the correct bits of X:  */
+             x = ((x & ~howto->dst_mask) | relocation);
+
+             /* Put the relocated value back in the object file:  */
+             bfd_put_32 (input_bfd, x, location);
+
+             rstat = overflow ? bfd_reloc_overflow : bfd_reloc_ok;
+            }
+        }
+#endif
+      else
+#endif /* THUMBEXTENSION */
+        rstat = _bfd_final_link_relocate (howto, input_bfd, input_section,
+                                          contents,
+                                          rel->r_vaddr - input_section->vma,
+                                          val, addend);
+#if 1 /* THUMBEXTENSION */
+      /* FIXME:
+        Is this the best way to fix up thumb addresses? krk@cygnus.com
+        Probably not, but it works, and if it works it don't need fixing!  nickc@cygnus.com */
+      /* Only perform this fix during the final link, not a relocatable link.  nickc@cygnus.com  */
+      if (! info->relocateable
+         && (rel->r_type == ARM_32 || rel->r_type == ARM_RVA32))
+       {
+         /* Determine if we need to set the bottom bit of a relocated address
+            because the address is the address of a Thumb code symbol.  */
+
+         int patchit = false;
+
+         if (h != NULL
+             && (   h->class == C_THUMBSTATFUNC
+                 || h->class == C_THUMBEXTFUNC))
+           {
+             patchit = true;
+           }
+         else if (sym != NULL
+                  && sym->n_scnum > N_UNDEF)
+           {
+             /* No hash entry - use the symbol instead.  */
+
+             if (   sym->n_sclass == C_THUMBSTATFUNC
+                 || sym->n_sclass == C_THUMBEXTFUNC)
+               patchit = true;
+           }
+
+         if (patchit)
+           {
+             bfd_byte * location = contents + rel->r_vaddr - input_section->vma;
+             bfd_vma    x        = bfd_get_32 (input_bfd, location);
+
+             bfd_put_32 (input_bfd, x | 1, location);
+           }
+       }
+#endif /* THUMBEXTENSION */
+
+      switch (rstat)
+       {
+       default:
+         abort ();
+       case bfd_reloc_ok:
+         break;
+       case bfd_reloc_outofrange:
+         (*_bfd_error_handler)
+           (_("%s: bad reloc address 0x%lx in section `%s'"),
+            bfd_get_filename (input_bfd),
+            (unsigned long) rel->r_vaddr,
+            bfd_get_section_name (input_bfd, input_section));
+         return false;
+       case bfd_reloc_overflow:
+         {
+           const char *name;
+           char buf[SYMNMLEN + 1];
+
+           if (symndx == -1)
+             name = "*ABS*";
+           else if (h != NULL)
+             name = h->root.root.string;
+           else
+             {
+               name = _bfd_coff_internal_syment_name (input_bfd, sym, buf);
+               if (name == NULL)
+                 return false;
+             }
+
+           if (! ((*info->callbacks->reloc_overflow)
+                  (info, name, howto->name, (bfd_vma) 0, input_bfd,
+                   input_section, rel->r_vaddr - input_section->vma)))
+             return false;
+         }
+       }
+    }
+
+  return true;
+}
+
+#ifndef COFF_IMAGE_WITH_PE
+
+boolean
+bfd_arm_allocate_interworking_sections (info)
+     struct bfd_link_info * info;
 {
-  TARGET_BIG_NAME,             /* name or coff-arm-big */
-  bfd_target_coff_flavour,
-  true,                                /* data byte order is big */
-  true,                                /* header byte order is big */
-
-  (HAS_RELOC | EXEC_P |                /* object flags */
-   HAS_LINENO | HAS_DEBUG |
-   HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
-
-  (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
-#ifdef TARGET_UNDERSCORE
-  TARGET_UNDERSCORE,           /* leading underscore */
-#else
-  0,                           /* leading underscore */
+  asection *                        s;
+  bfd_byte *                        foo;
+  struct coff_arm_link_hash_table * globals;
+#if 0
+  static char                       test_char = '1';
 #endif
-  '/',                         /* ar_pad_char */
-  15,                          /* ar_max_namelen */
-
-  2,                           /* minimum alignment power */
-  bfd_getb64, bfd_getb_signed_64, bfd_putb64,
-     bfd_getb32, bfd_getb_signed_32, bfd_putb32,
-     bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */
-  bfd_getb64, bfd_getb_signed_64, bfd_putb64,
-     bfd_getb32, bfd_getb_signed_32, bfd_putb32,
-     bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */
-
-/* Note that we allow an object file to be treated as a core file as well. */
-    {_bfd_dummy_target, i3coff_object_p, /* bfd_check_format */
-       bfd_generic_archive_p, i3coff_object_p},
-    {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */
-       bfd_false},
-    {bfd_false, coff_write_object_contents, /* bfd_write_contents */
-       _bfd_write_archive_contents, bfd_false},
-
-     BFD_JUMP_TABLE_GENERIC (coff),
-     BFD_JUMP_TABLE_COPY (coff),
-     BFD_JUMP_TABLE_CORE (_bfd_nocore),
-     BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff),
-     BFD_JUMP_TABLE_SYMBOLS (coff),
-     BFD_JUMP_TABLE_RELOCS (coff),
-     BFD_JUMP_TABLE_WRITE (coff),
-     BFD_JUMP_TABLE_LINK (coff),
-     BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
-
-  COFF_SWAP_TABLE,
-};
+
+  globals = coff_arm_hash_table (info);
+
+  BFD_ASSERT (globals != NULL);
+
+  if (globals->arm_glue_size != 0)
+    {
+      BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
+
+      s = bfd_get_section_by_name
+       (globals->bfd_of_glue_owner, ARM2THUMB_GLUE_SECTION_NAME);
+
+      BFD_ASSERT (s != NULL);
+
+      foo = (bfd_byte *) bfd_alloc
+       (globals->bfd_of_glue_owner, globals->arm_glue_size);
+#if 0
+      memset (foo, test_char, globals->arm_glue_size);
+#endif
+
+      s->_raw_size = s->_cooked_size = globals->arm_glue_size;
+      s->contents = foo;
+    }
+
+  if (globals->thumb_glue_size != 0)
+    {
+      BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
+
+      s = bfd_get_section_by_name
+       (globals->bfd_of_glue_owner, THUMB2ARM_GLUE_SECTION_NAME);
+
+      BFD_ASSERT (s != NULL);
+
+      foo = (bfd_byte *) bfd_alloc
+       (globals->bfd_of_glue_owner, globals->thumb_glue_size);
+#if 0
+      memset (foo, test_char, globals->thumb_glue_size);
 #endif
+
+      s->_raw_size = s->_cooked_size = globals->thumb_glue_size;
+      s->contents = foo;
+    }
+
+  return true;
+}
+
+static void
+record_arm_to_thumb_glue (info, h)
+     struct bfd_link_info *        info;
+     struct coff_link_hash_entry * h;
+{
+  const char *                      name = h->root.root.string;
+  register asection *               s;
+  char *                            tmp_name;
+  struct coff_link_hash_entry *     myh;
+  struct coff_arm_link_hash_table * globals;
+
+  globals = coff_arm_hash_table (info);
+
+  BFD_ASSERT (globals != NULL);
+  BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
+
+  s = bfd_get_section_by_name
+    (globals->bfd_of_glue_owner, ARM2THUMB_GLUE_SECTION_NAME);
+
+  BFD_ASSERT (s != NULL);
+
+  tmp_name = ((char *)
+             bfd_malloc (strlen (name) + strlen (ARM2THUMB_GLUE_ENTRY_NAME) + 1));
+
+  BFD_ASSERT (tmp_name);
+
+  sprintf (tmp_name, ARM2THUMB_GLUE_ENTRY_NAME, name);
+
+  myh = coff_link_hash_lookup
+    (coff_hash_table (info), tmp_name, false, false, true);
+
+  if (myh != NULL)
+    {
+      free (tmp_name);
+      return; /* we've already seen this guy */
+    }
+
+  /* The only trick here is using globals->arm_glue_size as the value. Even
+     though the section isn't allocated yet, this is where we will be putting
+     it.  */
+
+  bfd_coff_link_add_one_symbol (info, globals->bfd_of_glue_owner, tmp_name,
+                               BSF_GLOBAL,
+                               s, globals->arm_glue_size + 1,
+                               NULL, true, false,
+                               (struct bfd_link_hash_entry **) & myh);
+
+  free (tmp_name);
+
+  globals->arm_glue_size += ARM2THUMB_GLUE_SIZE;
+
+  return;
+}
+
+static void
+record_thumb_to_arm_glue (info, h)
+     struct bfd_link_info *        info;
+     struct coff_link_hash_entry * h;
+{
+  const char *                       name = h->root.root.string;
+  register asection *                s;
+  char *                             tmp_name;
+  struct coff_link_hash_entry *      myh;
+  struct coff_arm_link_hash_table *  globals;
+
+  globals = coff_arm_hash_table (info);
+
+  BFD_ASSERT (globals != NULL);
+  BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
+
+  s = bfd_get_section_by_name
+    (globals->bfd_of_glue_owner, THUMB2ARM_GLUE_SECTION_NAME);
+
+  BFD_ASSERT (s != NULL);
+
+  tmp_name = (char *) bfd_malloc (strlen (name) + strlen (THUMB2ARM_GLUE_ENTRY_NAME) + 1);
+
+  BFD_ASSERT (tmp_name);
+
+  sprintf (tmp_name, THUMB2ARM_GLUE_ENTRY_NAME, name);
+
+  myh = coff_link_hash_lookup
+    (coff_hash_table (info), tmp_name, false, false, true);
+
+  if (myh != NULL)
+    {
+      free (tmp_name);
+      return; /* we've already seen this guy */
+    }
+
+  bfd_coff_link_add_one_symbol (info, globals->bfd_of_glue_owner, tmp_name,
+                               BSF_GLOBAL, s, globals->thumb_glue_size + 1,
+                               NULL, true, false,
+                               (struct bfd_link_hash_entry **) & myh);
+
+  /* If we mark it 'thumb', the disassembler will do a better job.  */
+  myh->class = C_THUMBEXTFUNC;
+
+  free (tmp_name);
+
+  /* Allocate another symbol to mark where we switch to arm mode.  */
+
+#define CHANGE_TO_ARM "__%s_change_to_arm"
+#define BACK_FROM_ARM "__%s_back_from_arm"
+
+  tmp_name = (char *) bfd_malloc (strlen (name) + strlen (CHANGE_TO_ARM) + 1);
+
+  BFD_ASSERT (tmp_name);
+
+  sprintf (tmp_name, globals->support_old_code ? BACK_FROM_ARM : CHANGE_TO_ARM, name);
+
+  myh = NULL;
+
+  bfd_coff_link_add_one_symbol (info, globals->bfd_of_glue_owner, tmp_name,
+                               BSF_LOCAL, s, globals->thumb_glue_size
+                               + (globals->support_old_code ? 8 : 4),
+                               NULL, true, false,
+                               (struct bfd_link_hash_entry **) & myh);
+
+  free (tmp_name);
+
+  globals->thumb_glue_size += THUMB2ARM_GLUE_SIZE;
+
+  return;
+}
+
+/* Select a BFD to be used to hold the sections used by the glue code.
+   This function is called from the linker scripts in ld/emultempl/
+   {armcoff/pe}.em  */
+
+boolean
+bfd_arm_get_bfd_for_interworking (abfd, info)
+     bfd *                 abfd;
+     struct bfd_link_info * info;
+{
+  struct coff_arm_link_hash_table * globals;
+  flagword                         flags;
+  asection *                       sec;
+
+  /* If we are only performing a partial link do not bother
+     getting a bfd to hold the glue.  */
+  if (info->relocateable)
+    return true;
+
+  globals = coff_arm_hash_table (info);
+
+  BFD_ASSERT (globals != NULL);
+
+  if (globals->bfd_of_glue_owner != NULL)
+    return true;
+
+  sec = bfd_get_section_by_name (abfd, ARM2THUMB_GLUE_SECTION_NAME);
+
+  if (sec == NULL)
+    {
+      flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_CODE | SEC_READONLY;
+
+      sec = bfd_make_section (abfd, ARM2THUMB_GLUE_SECTION_NAME);
+
+      if (sec == NULL
+         || ! bfd_set_section_flags (abfd, sec, flags)
+         || ! bfd_set_section_alignment (abfd, sec, 2))
+       return false;
+    }
+
+  sec = bfd_get_section_by_name (abfd, THUMB2ARM_GLUE_SECTION_NAME);
+
+  if (sec == NULL)
+    {
+      flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_CODE | SEC_READONLY;
+
+      sec = bfd_make_section (abfd, THUMB2ARM_GLUE_SECTION_NAME);
+
+      if (sec == NULL
+         || ! bfd_set_section_flags (abfd, sec, flags)
+         || ! bfd_set_section_alignment (abfd, sec, 2))
+       return false;
+    }
+
+  /* Save the bfd for later use.  */
+  globals->bfd_of_glue_owner = abfd;
+
+  return true;
+}
+
+boolean
+bfd_arm_process_before_allocation (abfd, info, support_old_code)
+     bfd *                   abfd;
+     struct bfd_link_info *  info;
+     int                    support_old_code;
+{
+  asection * sec;
+  struct coff_arm_link_hash_table * globals;
+
+  /* If we are only performing a partial link do not bother
+     to construct any glue.  */
+  if (info->relocateable)
+    return true;
+
+  /* Here we have a bfd that is to be included on the link.  We have a hook
+     to do reloc rummaging, before section sizes are nailed down.  */
+
+  _bfd_coff_get_external_symbols (abfd);
+
+  globals = coff_arm_hash_table (info);
+
+  BFD_ASSERT (globals != NULL);
+  BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
+
+  globals->support_old_code = support_old_code;
+
+  /* Rummage around all the relocs and map the glue vectors.  */
+  sec = abfd->sections;
+
+  if (sec == NULL)
+    return true;
+
+  for (; sec != NULL; sec = sec->next)
+    {
+      struct internal_reloc * i;
+      struct internal_reloc * rel;
+
+      if (sec->reloc_count == 0)
+       continue;
+
+      /* Load the relocs.  */
+      /* FIXME: there may be a storage leak here.  */
+
+      i = _bfd_coff_read_internal_relocs (abfd, sec, 1, 0, 0, 0);
+
+      BFD_ASSERT (i != 0);
+
+      for (rel = i; rel < i + sec->reloc_count; ++rel)
+       {
+         unsigned short                 r_type  = rel->r_type;
+         long                           symndx;
+         struct coff_link_hash_entry *  h;
+
+         symndx = rel->r_symndx;
+
+         /* If the relocation is not against a symbol it cannot concern us.  */
+         if (symndx == -1)
+           continue;
+
+         /* If the index is outside of the range of our table, something has gone wrong.  */
+         if (symndx >= obj_conv_table_size (abfd))
+           {
+             _bfd_error_handler (_("%s: illegal symbol index in reloc: %d"),
+                                 bfd_get_filename (abfd), symndx);
+             continue;
+           }
+
+         h = obj_coff_sym_hashes (abfd)[symndx];
+
+         /* If the relocation is against a static symbol it must be within
+            the current section and so cannot be a cross ARM/Thumb relocation.  */
+         if (h == NULL)
+           continue;
+
+         switch (r_type)
+           {
+           case ARM_26:
+             /* This one is a call from arm code.  We need to look up
+                the target of the call. If it is a thumb target, we
+                insert glue.  */
+
+             if (h->class == C_THUMBEXTFUNC)
+               record_arm_to_thumb_glue (info, h);
+             break;
+
+#ifndef ARM_WINCE
+           case ARM_THUMB23:
+             /* This one is a call from thumb code.  We used to look
+                for ARM_THUMB9 and ARM_THUMB12 as well.  We need to look
+                up the target of the call. If it is an arm target, we
+                insert glue.  If the symbol does not exist it will be
+                given a class of C_EXT and so we will generate a stub
+                for it.  This is not really a problem, since the link
+                is doomed anyway.  */
+
+             switch (h->class)
+               {
+               case C_EXT:
+               case C_STAT:
+               case C_LABEL:
+                 record_thumb_to_arm_glue (info, h);
+                 break;
+               default:
+                 ;
+               }
+             break;
+#endif
+
+           default:
+             break;
+           }
+       }
+    }
+
+  return true;
+}
+
+#endif /* ! defined (COFF_IMAGE_WITH_PE) */
+
+#define coff_bfd_reloc_type_lookup             coff_arm_reloc_type_lookup
+#define coff_relocate_section                  coff_arm_relocate_section
+#define coff_bfd_is_local_label_name           coff_arm_is_local_label_name
+#define coff_adjust_symndx                     coff_arm_adjust_symndx
+#define coff_link_output_has_begun             coff_arm_link_output_has_begun
+#define coff_final_link_postscript             coff_arm_final_link_postscript
+#define coff_bfd_merge_private_bfd_data                coff_arm_merge_private_bfd_data
+#define coff_bfd_print_private_bfd_data                coff_arm_print_private_bfd_data
+#define coff_bfd_set_private_flags              _bfd_coff_arm_set_private_flags
+#define coff_bfd_copy_private_bfd_data          coff_arm_copy_private_bfd_data
+#define coff_bfd_link_hash_table_create                coff_arm_link_hash_table_create
+
+/* When doing a relocateable link, we want to convert ARM26 relocs
+   into ARM26D relocs.  */
+
+static boolean
+coff_arm_adjust_symndx (obfd, info, ibfd, sec, irel, adjustedp)
+     bfd *obfd ATTRIBUTE_UNUSED;
+     struct bfd_link_info *info ATTRIBUTE_UNUSED;
+     bfd *ibfd;
+     asection *sec;
+     struct internal_reloc *irel;
+     boolean *adjustedp;
+{
+  if (irel->r_type == 3)
+    {
+      struct coff_link_hash_entry *h;
+
+      h = obj_coff_sym_hashes (ibfd)[irel->r_symndx];
+      if (h != NULL
+         && (h->root.type == bfd_link_hash_defined
+             || h->root.type == bfd_link_hash_defweak)
+         && h->root.u.def.section->output_section == sec->output_section)
+       irel->r_type = 7;
+    }
+  *adjustedp = false;
+  return true;
+}
+
+/* Called when merging the private data areas of two BFDs.
+   This is important as it allows us to detect if we are
+   attempting to merge binaries compiled for different ARM
+   targets, eg different CPUs or differents APCS's.     */
+
+static boolean
+coff_arm_merge_private_bfd_data (ibfd, obfd)
+     bfd *   ibfd;
+     bfd *   obfd;
+{
+  BFD_ASSERT (ibfd != NULL && obfd != NULL);
+
+  if (ibfd == obfd)
+    return true;
+
+  /* If the two formats are different we cannot merge anything.
+     This is not an error, since it is permissable to change the
+     input and output formats.  */
+  if (   ibfd->xvec->flavour != bfd_target_coff_flavour
+      || obfd->xvec->flavour != bfd_target_coff_flavour)
+    return true;
+
+  /* Verify that the APCS is the same for the two BFDs */
+  if (APCS_SET (ibfd))
+    {
+      if (APCS_SET (obfd))
+       {
+         /* If the src and dest have different APCS flag bits set, fail.  */
+         if (APCS_26_FLAG (obfd) != APCS_26_FLAG (ibfd))
+           {
+             _bfd_error_handler
+               /* xgettext: c-format */
+               (_("%s: ERROR: compiled for APCS-%d whereas target %s uses APCS-%d"),
+                bfd_get_filename (ibfd), APCS_26_FLAG (ibfd) ? 26 : 32,
+                bfd_get_filename (obfd), APCS_26_FLAG (obfd) ? 26 : 32
+                );
+
+             bfd_set_error (bfd_error_wrong_format);
+             return false;
+           }
+
+         if (APCS_FLOAT_FLAG (obfd) != APCS_FLOAT_FLAG (ibfd))
+           {
+             const char *msg;
+
+             if (APCS_FLOAT_FLAG (ibfd))
+               /* xgettext: c-format */
+               msg = _("%s: ERROR: passes floats in float registers whereas target %s uses integer registers");
+             else
+               /* xgettext: c-format */
+               msg = _("%s: ERROR: passes floats in integer registers whereas target %s uses float registers");
+
+             _bfd_error_handler (msg, bfd_get_filename (ibfd),
+                                 bfd_get_filename (obfd));
+
+             bfd_set_error (bfd_error_wrong_format);
+             return false;
+           }
+
+         if (PIC_FLAG (obfd) != PIC_FLAG (ibfd))
+           {
+             const char * msg;
+
+             if (PIC_FLAG (ibfd))
+               /* xgettext: c-format */
+               msg = _("%s: ERROR: compiled as position independent code, whereas target %s is absolute position");
+             else
+               /* xgettext: c-format */
+               msg = _("%s: ERROR: compiled as absolute position code, whereas target %s is position independent");
+             _bfd_error_handler (msg, bfd_get_filename (ibfd),
+                                 bfd_get_filename (obfd));
+
+             bfd_set_error (bfd_error_wrong_format);
+             return false;
+           }
+       }
+      else
+       {
+         SET_APCS_FLAGS (obfd, APCS_26_FLAG (ibfd) | APCS_FLOAT_FLAG (ibfd) | PIC_FLAG (ibfd));
+
+         /* Set up the arch and fields as well as these are probably wrong.  */
+         bfd_set_arch_mach (obfd, bfd_get_arch (ibfd), bfd_get_mach (ibfd));
+       }
+    }
+
+  /* Check the interworking support.  */
+  if (INTERWORK_SET (ibfd))
+    {
+      if (INTERWORK_SET (obfd))
+       {
+         /* If the src and dest differ in their interworking issue a warning.  */
+         if (INTERWORK_FLAG (obfd) != INTERWORK_FLAG (ibfd))
+           {
+             const char * msg;
+
+             if (INTERWORK_FLAG (ibfd))
+               /* xgettext: c-format */
+               msg = _("Warning: input file %s supports interworking, whereas %s does not.");
+             else
+               /* xgettext: c-format */
+               msg = _("Warning: input file %s does not support interworking, whereas %s does.");
+
+             _bfd_error_handler (msg, bfd_get_filename (ibfd),
+                                 bfd_get_filename (obfd));
+           }
+       }
+      else
+       {
+         SET_INTERWORK_FLAG (obfd, INTERWORK_FLAG (ibfd));
+       }
+    }
+
+  return true;
+}
+
+/* Display the flags field.  */
+
+static boolean
+coff_arm_print_private_bfd_data (abfd, ptr)
+     bfd *   abfd;
+     PTR     ptr;
+{
+  FILE * file = (FILE *) ptr;
+
+  BFD_ASSERT (abfd != NULL && ptr != NULL);
+
+  /* xgettext:c-format */
+  fprintf (file, _("private flags = %x:"), coff_data (abfd)->flags);
+
+  if (APCS_SET (abfd))
+    {
+      /* xgettext: APCS is ARM Prodecure Call Standard, it should not be translated.  */
+      fprintf (file, " [APCS-%d]", APCS_26_FLAG (abfd) ? 26 : 32);
+
+      if (APCS_FLOAT_FLAG (abfd))
+       fprintf (file, _(" [floats passed in float registers]"));
+      else
+       fprintf (file, _(" [floats passed in integer registers]"));
+
+      if (PIC_FLAG (abfd))
+       fprintf (file, _(" [position independent]"));
+      else
+       fprintf (file, _(" [absolute position]"));
+    }
+
+  if (! INTERWORK_SET (abfd))
+    fprintf (file, _(" [interworking flag not initialised]"));
+  else if (INTERWORK_FLAG (abfd))
+    fprintf (file, _(" [interworking supported]"));
+  else
+    fprintf (file, _(" [interworking not supported]"));
+
+  fputc ('\n', file);
+
+  return true;
+}
+
+/* Copies the given flags into the coff_tdata.flags field.
+   Typically these flags come from the f_flags[] field of
+   the COFF filehdr structure, which contains important,
+   target specific information.
+   Note: Although this function is static, it is explicitly
+   called from both coffcode.h and peicode.h.  */
+
+static boolean
+_bfd_coff_arm_set_private_flags (abfd, flags)
+       bfd *      abfd;
+       flagword   flags;
+{
+  flagword flag;
+
+  BFD_ASSERT (abfd != NULL);
+
+  flag = (flags & F_APCS26) ? F_APCS_26 : 0;
+
+  /* Make sure that the APCS field has not been initialised to the opposite
+     value.  */
+  if (APCS_SET (abfd)
+      && (   (APCS_26_FLAG    (abfd) != flag)
+         || (APCS_FLOAT_FLAG (abfd) != (flags & F_APCS_FLOAT))
+         || (PIC_FLAG        (abfd) != (flags & F_PIC))
+         ))
+    return false;
+
+  flag |= (flags & (F_APCS_FLOAT | F_PIC));
+
+  SET_APCS_FLAGS (abfd, flag);
+
+  flag = (flags & F_INTERWORK);
+
+  /* If the BFD has already had its interworking flag set, but it
+     is different from the value that we have been asked to set,
+     then assume that that merged code will not support interworking
+     and set the flag accordingly.  */
+  if (INTERWORK_SET (abfd) && (INTERWORK_FLAG (abfd) != flag))
+    {
+      if (flag)
+       /* xgettext: c-format */
+       _bfd_error_handler (_("Warning: Not setting interworking flag of %s, since it has already been specified as non-interworking"),
+                           bfd_get_filename (abfd));
+      else
+       /* xgettext: c-format */
+       _bfd_error_handler (_("Warning: Clearing the interworking flag of %s due to outside request"),
+                           bfd_get_filename (abfd));
+      flag = 0;
+    }
+
+  SET_INTERWORK_FLAG (abfd, flag);
+
+  return true;
+}
+
+/* Copy the important parts of the target specific data
+   from one instance of a BFD to another.  */
+
+static boolean
+coff_arm_copy_private_bfd_data (src, dest)
+     bfd *  src;
+     bfd *  dest;
+{
+  BFD_ASSERT (src != NULL && dest != NULL);
+
+  if (src == dest)
+    return true;
+
+  /* If the destination is not in the same format as the source, do not do
+     the copy.  */
+  if (src->xvec != dest->xvec)
+    return true;
+
+  /* copy the flags field */
+  if (APCS_SET (src))
+    {
+      if (APCS_SET (dest))
+       {
+         /* If the src and dest have different APCS flag bits set, fail.  */
+         if (APCS_26_FLAG (dest) != APCS_26_FLAG (src))
+           return false;
+
+         if (APCS_FLOAT_FLAG (dest) != APCS_FLOAT_FLAG (src))
+           return false;
+
+         if (PIC_FLAG (dest) != PIC_FLAG (src))
+           return false;
+       }
+      else
+       SET_APCS_FLAGS (dest, APCS_26_FLAG (src) | APCS_FLOAT_FLAG (src)
+                       | PIC_FLAG (src));
+    }
+
+  if (INTERWORK_SET (src))
+    {
+      if (INTERWORK_SET (dest))
+       {
+         /* If the src and dest have different interworking flags then turn
+            off the interworking bit.  */
+         if (INTERWORK_FLAG (dest) != INTERWORK_FLAG (src))
+           {
+             if (INTERWORK_FLAG (dest))
+               {
+                 /* xgettext:c-format */
+                 _bfd_error_handler (("Warning: Clearing the interworking bit of %s, because the non-interworking code in %s has been copied into it"),
+                                     bfd_get_filename (dest),
+                                     bfd_get_filename (src));
+               }
+
+             SET_INTERWORK_FLAG (dest, 0);
+           }
+       }
+      else
+       {
+         SET_INTERWORK_FLAG (dest, INTERWORK_FLAG (src));
+       }
+    }
+
+  return true;
+}
+
+/* Note:  the definitions here of LOCAL_LABEL_PREFIX and USER_LABEL_PREIFX
+ *must* match the definitions in gcc/config/arm/coff.h and semi.h */
+#define LOCAL_LABEL_PREFIX "."
+#ifndef USER_LABEL_PREFIX
+#define USER_LABEL_PREFIX "_"
+#endif
+
+/* Like _bfd_coff_is_local_label_name, but
+   a) test against USER_LABEL_PREFIX, to avoid stripping labels known to be
+      non-local.
+   b) Allow other prefixes than ".", e.g. an empty prefix would cause all
+      labels of the form Lxxx to be stripped.  */
+static boolean
+coff_arm_is_local_label_name (abfd, name)
+     bfd *        abfd ATTRIBUTE_UNUSED;
+     const char * name;
+{
+#ifdef USER_LABEL_PREFIX
+  if (USER_LABEL_PREFIX[0] != 0)
+    {
+      if (strncmp (name, USER_LABEL_PREFIX, strlen (USER_LABEL_PREFIX)) == 0)
+       return false;
+    }
+#endif
+
+#ifdef LOCAL_LABEL_PREFIX
+  /* If there is a prefix for local labels then look for this.
+     If the prefix exists, but it is empty, then ignore the test.  */
+
+  if (LOCAL_LABEL_PREFIX[0] != 0)
+    {
+      int len = strlen (LOCAL_LABEL_PREFIX);
+
+      if (strncmp (name, LOCAL_LABEL_PREFIX, len) != 0)
+       return false;
+
+      /* Perform the checks below for the rest of the name.  */
+      name += len;
+    }
+#endif
+
+  return name[0] == 'L';
+}
+
+/* This piece of machinery exists only to guarantee that the bfd that holds
+   the glue section is written last.
+
+   This does depend on bfd_make_section attaching a new section to the
+   end of the section list for the bfd.
+
+   krk@cygnus.com  */
+
+static boolean
+coff_arm_link_output_has_begun (sub, info)
+     bfd * sub;
+     struct coff_final_link_info * info;
+{
+  return (sub->output_has_begun
+         || sub == coff_arm_hash_table (info->info)->bfd_of_glue_owner);
+}
+
+static boolean
+coff_arm_final_link_postscript (abfd, pfinfo)
+     bfd * abfd ATTRIBUTE_UNUSED;
+     struct coff_final_link_info * pfinfo;
+{
+  struct coff_arm_link_hash_table * globals;
+
+  globals = coff_arm_hash_table (pfinfo->info);
+
+  BFD_ASSERT (globals != NULL);
+
+  if (globals->bfd_of_glue_owner != NULL)
+    {
+      if (! _bfd_coff_link_input_bfd (pfinfo, globals->bfd_of_glue_owner))
+       return false;
+
+      globals->bfd_of_glue_owner->output_has_begun = true;
+    }
+
+  return true;
+}
+
+#include "coffcode.h"
+
+#ifndef TARGET_LITTLE_SYM
+#define TARGET_LITTLE_SYM armcoff_little_vec
+#endif
+#ifndef TARGET_LITTLE_NAME
+#define TARGET_LITTLE_NAME "coff-arm-little"
+#endif
+#ifndef TARGET_BIG_SYM
+#define TARGET_BIG_SYM armcoff_big_vec
+#endif
+#ifndef TARGET_BIG_NAME
+#define TARGET_BIG_NAME "coff-arm-big"
+#endif
+
+#ifndef TARGET_UNDERSCORE
+#define TARGET_UNDERSCORE 0
+#endif
+
+#ifdef COFF_WITH_PE
+#define EXTRA_S_FLAGS (SEC_LINK_ONCE | SEC_LINK_DUPLICATES)
+#else
+#define EXTRA_S_FLAGS 0
+#endif
+
+/* Forward declaration for use initialising alternative_target field.  */
+extern const bfd_target TARGET_BIG_SYM ;
+
+/* Target vectors.  */
+CREATE_LITTLE_COFF_TARGET_VEC (TARGET_LITTLE_SYM, TARGET_LITTLE_NAME, D_PAGED, EXTRA_S_FLAGS, TARGET_UNDERSCORE, & TARGET_BIG_SYM)
+CREATE_BIG_COFF_TARGET_VEC (TARGET_BIG_SYM, TARGET_BIG_NAME, D_PAGED, EXTRA_S_FLAGS, TARGET_UNDERSCORE, & TARGET_LITTLE_SYM)
+
This page took 0.098388 seconds and 4 git commands to generate.