Add 'Chnages in 2.13' to NEWS files.
[deliverable/binutils-gdb.git] / bfd / coff-rs6000.c
index 932e437626d01f800dc12fd6446144df25f475da..025372d11633881b0f279219251921f38286d024 100644 (file)
@@ -1,6 +1,5 @@
 /* BFD back-end for IBM RS/6000 "XCOFF" files.
-   Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001
+   Copyright 1990-1999, 2000, 2001, 2002
    Free Software Foundation, Inc.
    FIXME: Can someone provide a transliteration of this name into ASCII?
    Using the following chars caused a compiler warning on HIUX (so I replaced
@@ -46,7 +45,7 @@ extern boolean _bfd_xcoff_slurp_armap PARAMS ((bfd *));
 extern const bfd_target *_bfd_xcoff_archive_p PARAMS ((bfd *));
 extern PTR _bfd_xcoff_read_ar_hdr PARAMS ((bfd *));
 extern bfd *_bfd_xcoff_openr_next_archived_file PARAMS ((bfd *, bfd *));
-extern int _bfd_xcoff_generic_stat_arch_elt PARAMS ((bfd *, struct stat *));
+extern int _bfd_xcoff_stat_arch_elt PARAMS ((bfd *, struct stat *));
 extern boolean _bfd_xcoff_write_armap
   PARAMS ((bfd *, unsigned int, struct orl *, unsigned int, int));
 extern boolean _bfd_xcoff_write_archive_contents PARAMS ((bfd *));
@@ -55,9 +54,11 @@ extern void _bfd_xcoff_swap_sym_in PARAMS ((bfd *, PTR, PTR));
 extern unsigned int _bfd_xcoff_swap_sym_out PARAMS ((bfd *, PTR, PTR));
 extern void _bfd_xcoff_swap_aux_in PARAMS ((bfd *, PTR, int, int, int, int, PTR));
 extern unsigned int _bfd_xcoff_swap_aux_out PARAMS ((bfd *, PTR, int, int, int, int, PTR));
+static void xcoff_swap_reloc_in PARAMS ((bfd *, PTR, PTR));
+static unsigned int xcoff_swap_reloc_out PARAMS ((bfd *, PTR, PTR));
 
-/* Forward declare _bfd_xcoff_rtype2howto for coffcode.h macro.  */
-void _bfd_xcoff_rtype2howto PARAMS ((arelent *, struct internal_reloc *));
+/* Forward declare xcoff_rtype2howto for coffcode.h macro.  */
+void xcoff_rtype2howto PARAMS ((arelent *, struct internal_reloc *));
 
 /* coffcode.h needs these to be defined.  */
 #define RS6000COFF_C 1
@@ -75,14 +76,15 @@ void _bfd_xcoff_rtype2howto PARAMS ((arelent *, struct internal_reloc *));
 #define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (3)
 #define COFF_LONG_FILENAMES
 #define NO_COFF_SYMBOLS
-#define RTYPE2HOWTO(cache_ptr, dst) _bfd_xcoff_rtype2howto (cache_ptr, dst)
+#define RTYPE2HOWTO(cache_ptr, dst) xcoff_rtype2howto (cache_ptr, dst)
 #define coff_mkobject _bfd_xcoff_mkobject
 #define coff_bfd_copy_private_bfd_data _bfd_xcoff_copy_private_bfd_data
 #define coff_bfd_is_local_label_name _bfd_xcoff_is_local_label_name
 #define coff_bfd_reloc_type_lookup _bfd_xcoff_reloc_type_lookup
 #ifdef AIX_CORE
-extern const bfd_target * rs6000coff_core_p ();
-extern boolean rs6000coff_core_file_matches_executable_p ();
+extern const bfd_target * rs6000coff_core_p PARAMS ((bfd *abfd));
+extern boolean rs6000coff_core_file_matches_executable_p 
+  PARAMS ((bfd *cbfd, bfd *ebfd));
 extern char *rs6000coff_core_file_failing_command PARAMS ((bfd *abfd));
 extern int rs6000coff_core_file_failing_signal PARAMS ((bfd *abfd));
 #define CORE_FILE_P rs6000coff_core_p
@@ -105,6 +107,9 @@ extern int rs6000coff_core_file_failing_signal PARAMS ((bfd *abfd));
 #define coff_SWAP_sym_out _bfd_xcoff_swap_sym_out
 #define coff_SWAP_aux_in _bfd_xcoff_swap_aux_in
 #define coff_SWAP_aux_out _bfd_xcoff_swap_aux_out
+#define coff_swap_reloc_in xcoff_swap_reloc_in
+#define coff_swap_reloc_out xcoff_swap_reloc_out
+#define NO_COFF_RELOCS
 
 #include "coffcode.h"
 
@@ -113,9 +118,6 @@ extern int rs6000coff_core_file_failing_signal PARAMS ((bfd *abfd));
 static const char *normalize_filename PARAMS ((bfd *));
 static boolean xcoff_write_armap_old
   PARAMS ((bfd *, unsigned int, struct orl *, unsigned int, int));
-static boolean xcoff_write_one_armap_big
-  PARAMS ((bfd *, struct orl *, unsigned int, unsigned int, unsigned int,
-          int, const char *, char *));
 static boolean xcoff_write_armap_big
   PARAMS ((bfd *, unsigned int, struct orl *, unsigned int, int));
 static boolean xcoff_write_archive_contents_old PARAMS ((bfd *));
@@ -146,6 +148,65 @@ static bfd_vma xcoff_loader_symbol_offset
   PARAMS ((bfd *, struct internal_ldhdr *));
 static bfd_vma xcoff_loader_reloc_offset
   PARAMS ((bfd *, struct internal_ldhdr *));
+static boolean xcoff_generate_rtinit 
+  PARAMS((bfd *, const char *, const char *, boolean));
+static boolean do_pad PARAMS((bfd *, unsigned int));
+static boolean do_copy PARAMS((bfd *, bfd *));
+static boolean do_shared_object_padding PARAMS ((bfd *, bfd *, ufile_ptr *, int));
+
+/* Relocation functions */
+static boolean xcoff_reloc_type_br PARAMS ((XCOFF_RELOC_FUNCTION_ARGS));
+
+static boolean xcoff_complain_overflow_dont_func 
+  PARAMS ((XCOFF_COMPLAIN_FUNCTION_ARGS));
+static boolean xcoff_complain_overflow_bitfield_func
+  PARAMS ((XCOFF_COMPLAIN_FUNCTION_ARGS));
+static boolean xcoff_complain_overflow_signed_func
+  PARAMS ((XCOFF_COMPLAIN_FUNCTION_ARGS));
+static boolean xcoff_complain_overflow_unsigned_func
+  PARAMS ((XCOFF_COMPLAIN_FUNCTION_ARGS));
+
+boolean (*xcoff_calculate_relocation[XCOFF_MAX_CALCULATE_RELOCATION])
+     (XCOFF_RELOC_FUNCTION_ARGS) =
+{
+  xcoff_reloc_type_pos,  /* R_POS   (0x00) */
+  xcoff_reloc_type_neg,  /* R_NEG   (0x01) */
+  xcoff_reloc_type_rel,  /* R_REL   (0x02) */
+  xcoff_reloc_type_toc,  /* R_TOC   (0x03) */
+  xcoff_reloc_type_fail, /* R_RTB   (0x04) */
+  xcoff_reloc_type_toc,  /* R_GL    (0x05) */
+  xcoff_reloc_type_toc,  /* R_TCL   (0x06) */
+  xcoff_reloc_type_fail, /*         (0x07) */
+  xcoff_reloc_type_ba,   /* R_BA    (0x08) */
+  xcoff_reloc_type_fail, /*         (0x09) */
+  xcoff_reloc_type_br,   /* R_BR    (0x0a) */
+  xcoff_reloc_type_fail, /*         (0x0b) */
+  xcoff_reloc_type_pos,  /* R_RL    (0x0c) */
+  xcoff_reloc_type_pos,  /* R_RLA   (0x0d) */
+  xcoff_reloc_type_fail, /*         (0x0e) */
+  xcoff_reloc_type_noop, /* R_REF   (0x0f) */
+  xcoff_reloc_type_fail, /*         (0x10) */
+  xcoff_reloc_type_fail, /*         (0x11) */
+  xcoff_reloc_type_toc,  /* R_TRL   (0x12) */
+  xcoff_reloc_type_toc,  /* R_TRLA  (0x13) */
+  xcoff_reloc_type_fail, /* R_RRTBI (0x14) */
+  xcoff_reloc_type_fail, /* R_RRTBA (0x15) */
+  xcoff_reloc_type_ba,   /* R_CAI   (0x16) */
+  xcoff_reloc_type_crel, /* R_CREL  (0x17) */
+  xcoff_reloc_type_ba,   /* R_RBA   (0x18) */
+  xcoff_reloc_type_ba,   /* R_RBAC  (0x19) */
+  xcoff_reloc_type_br,   /* R_RBR   (0x1a) */
+  xcoff_reloc_type_ba,   /* R_RBRC  (0x1b) */
+};
+
+boolean (*xcoff_complain_overflow[XCOFF_MAX_COMPLAIN_OVERFLOW])
+     (XCOFF_COMPLAIN_FUNCTION_ARGS) = 
+{
+  xcoff_complain_overflow_dont_func,
+  xcoff_complain_overflow_bitfield_func,
+  xcoff_complain_overflow_signed_func,
+  xcoff_complain_overflow_unsigned_func,
+};
 
 /* We use our own tdata type.  Its first field is the COFF tdata type,
    so the COFF routines are compatible.  */
@@ -176,7 +237,7 @@ _bfd_xcoff_mkobject (abfd)
   xcoff_data (abfd)->debug_indices = NULL;
 
   /* text section alignment is different than the default */
-  /* xcoff_data (abfd)->text_align_power = 5; */
+  bfd_xcoff_text_align_power (abfd) = 2;
 
   return true;
 }
@@ -217,8 +278,8 @@ _bfd_xcoff_copy_private_bfd_data (ibfd, obfd)
       else
        ox->snentry = sec->output_section->target_index;
     }
-  ox->text_align_power = ix->text_align_power;
-  ox->data_align_power = ix->data_align_power;
+  bfd_xcoff_text_align_power (obfd) = bfd_xcoff_text_align_power (ibfd);
+  bfd_xcoff_data_align_power (obfd) = bfd_xcoff_data_align_power (ibfd);
   ox->modtype = ix->modtype;
   ox->cputype = ix->cputype;
   ox->maxdata = ix->maxdata;
@@ -517,7 +578,7 @@ end:
 reloc_howto_type xcoff_howto_table[] =
 {
   /* Standard 32 bit relocation.  */
-  HOWTO (0,                    /* type */
+  HOWTO (R_POS,                        /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         32,                    /* bitsize */
@@ -532,7 +593,7 @@ reloc_howto_type xcoff_howto_table[] =
         false),                /* pcrel_offset */
 
   /* 32 bit relocation, but store negative value.  */
-  HOWTO (1,                    /* type */
+  HOWTO (R_NEG,                        /* type */
         0,                     /* rightshift */
         -2,                    /* size (0 = byte, 1 = short, 2 = long) */
         32,                    /* bitsize */
@@ -547,7 +608,7 @@ reloc_howto_type xcoff_howto_table[] =
         false),                /* pcrel_offset */
 
   /* 32 bit PC relative relocation.  */
-  HOWTO (2,                    /* type */
+  HOWTO (R_REL,                        /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         32,                    /* bitsize */
@@ -562,7 +623,7 @@ reloc_howto_type xcoff_howto_table[] =
         false),                /* pcrel_offset */
 
   /* 16 bit TOC relative relocation.  */
-  HOWTO (3,                    /* type */
+  HOWTO (R_TOC,                        /* type */
         0,                     /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
@@ -577,7 +638,7 @@ reloc_howto_type xcoff_howto_table[] =
         false),                /* pcrel_offset */
 
   /* I don't really know what this is.  */
-  HOWTO (4,                    /* type */
+  HOWTO (R_RTB,                        /* type */
         1,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         32,                    /* bitsize */
@@ -592,7 +653,7 @@ reloc_howto_type xcoff_howto_table[] =
         false),                /* pcrel_offset */
 
   /* External TOC relative symbol.  */
-  HOWTO (5,                    /* type */
+  HOWTO (R_GL,                 /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
@@ -607,7 +668,7 @@ reloc_howto_type xcoff_howto_table[] =
         false),                /* pcrel_offset */
 
   /* Local TOC relative symbol.  */
-  HOWTO (6,                    /* type */
+  HOWTO (R_TCL,                        /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
@@ -624,7 +685,7 @@ reloc_howto_type xcoff_howto_table[] =
   EMPTY_HOWTO (7),
 
   /* Non modifiable absolute branch.  */
-  HOWTO (8,                    /* type */
+  HOWTO (R_BA,                 /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         26,                    /* bitsize */
@@ -632,7 +693,7 @@ reloc_howto_type xcoff_howto_table[] =
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
         0,                     /* special_function */
-        "R_BA",                /* name */
+        "R_BA_26",             /* name */
         true,                  /* partial_inplace */
         0x3fffffc,             /* src_mask */
         0x3fffffc,             /* dst_mask */
@@ -641,7 +702,7 @@ reloc_howto_type xcoff_howto_table[] =
   EMPTY_HOWTO (9),
 
   /* Non modifiable relative branch.  */
-  HOWTO (0xa,                  /* type */
+  HOWTO (R_BR,                 /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         26,                    /* bitsize */
@@ -658,7 +719,7 @@ reloc_howto_type xcoff_howto_table[] =
   EMPTY_HOWTO (0xb),
 
   /* Indirect load.  */
-  HOWTO (0xc,                  /* type */
+  HOWTO (R_RL,                 /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
@@ -673,7 +734,7 @@ reloc_howto_type xcoff_howto_table[] =
         false),                /* pcrel_offset */
 
   /* Load address.  */
-  HOWTO (0xd,                  /* type */
+  HOWTO (R_RLA,                        /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
@@ -690,7 +751,7 @@ reloc_howto_type xcoff_howto_table[] =
   EMPTY_HOWTO (0xe),
 
   /* Non-relocating reference.  */
-  HOWTO (0xf,                  /* type */
+  HOWTO (R_REF,                        /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         32,                    /* bitsize */
@@ -708,7 +769,7 @@ reloc_howto_type xcoff_howto_table[] =
   EMPTY_HOWTO (0x11),
 
   /* TOC relative indirect load.  */
-  HOWTO (0x12,                 /* type */
+  HOWTO (R_TRL,                        /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
@@ -723,7 +784,7 @@ reloc_howto_type xcoff_howto_table[] =
         false),                /* pcrel_offset */
 
   /* TOC relative load address.  */
-  HOWTO (0x13,                 /* type */
+  HOWTO (R_TRLA,                /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
@@ -738,7 +799,7 @@ reloc_howto_type xcoff_howto_table[] =
         false),                /* pcrel_offset */
 
   /* Modifiable relative branch.  */
-  HOWTO (0x14,                 /* type */
+  HOWTO (R_RRTBI,                /* type */
         1,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         32,                    /* bitsize */
@@ -753,7 +814,7 @@ reloc_howto_type xcoff_howto_table[] =
         false),                /* pcrel_offset */
 
   /* Modifiable absolute branch.  */
-  HOWTO (0x15,                 /* type */
+  HOWTO (R_RRTBA,                /* type */
         1,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         32,                    /* bitsize */
@@ -768,7 +829,7 @@ reloc_howto_type xcoff_howto_table[] =
         false),                /* pcrel_offset */
 
   /* Modifiable call absolute indirect.  */
-  HOWTO (0x16,                 /* type */
+  HOWTO (R_CAI,                        /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
@@ -783,7 +844,7 @@ reloc_howto_type xcoff_howto_table[] =
         false),                /* pcrel_offset */
 
   /* Modifiable call relative.  */
-  HOWTO (0x17,                 /* type */
+  HOWTO (R_CREL,                /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
@@ -798,7 +859,7 @@ reloc_howto_type xcoff_howto_table[] =
         false),                /* pcrel_offset */
 
   /* Modifiable branch absolute.  */
-  HOWTO (0x18,                 /* type */
+  HOWTO (R_RBA,                        /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         26,                    /* bitsize */
@@ -813,7 +874,7 @@ reloc_howto_type xcoff_howto_table[] =
         false),                /* pcrel_offset */
 
   /* Modifiable branch absolute.  */
-  HOWTO (0x19,                 /* type */
+  HOWTO (R_RBAC,                /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         32,                    /* bitsize */
@@ -828,7 +889,7 @@ reloc_howto_type xcoff_howto_table[] =
         false),                /* pcrel_offset */
 
   /* Modifiable branch relative.  */
-  HOWTO (0x1a,                 /* type */
+  HOWTO (R_RBR,                        /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         26,                    /* bitsize */
@@ -836,14 +897,14 @@ reloc_howto_type xcoff_howto_table[] =
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
         0,                     /* special_function */
-        "R_RBR",               /* name */
+        "R_RBR_26",            /* name */
         true,                  /* partial_inplace */
         0xffff,                /* src_mask */
         0xffff,                /* dst_mask */
         false),                /* pcrel_offset */
 
   /* Modifiable branch absolute.  */
-  HOWTO (0x1b,                 /* type */
+  HOWTO (R_RBRC,                /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
@@ -857,36 +918,75 @@ reloc_howto_type xcoff_howto_table[] =
         0xffff,                /* dst_mask */
         false),                /* pcrel_offset */
 
-  HOWTO (0,                     /* type */
-         0,                     /* rightshift */
-         4,                     /* size (0 = byte, 1 = short, 2 = long) */
-         64,                    /* bitsize */
-         false,                 /* pc_relative */
-         0,                     /* bitpos */
-         complain_overflow_bitfield, /* complain_on_overflow */
-         0,                     /* special_function */
-         "R_POS",               /* name */
-         true,                  /* partial_inplace */
-         MINUS_ONE,             /* src_mask */
-        MINUS_ONE,             /* dst_mask */
-        false)                 /* pcrel_offset */
+  /* 16 bit Non modifiable absolute branch.  */
+  HOWTO (R_BA,                 /* type */
+        0,                     /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield, /* complain_on_overflow */
+        0,                     /* special_function */
+        "R_BA_16",             /* name */
+        true,                  /* partial_inplace */
+        0xfffc,                /* src_mask */
+        0xfffc,                /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* Modifiable branch relative.  */
+  HOWTO (R_RBR,                        /* type */
+        0,                     /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed, /* complain_on_overflow */
+        0,                     /* special_function */
+        "R_RBR_16",            /* name */
+        true,                  /* partial_inplace */
+        0xffff,                /* src_mask */
+        0xffff,                /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* Modifiable branch relative.  */
+  HOWTO (R_RBA,                        /* type */
+        0,                     /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed, /* complain_on_overflow */
+        0,                     /* special_function */
+        "R_RBA_16",            /* name */
+        true,                  /* partial_inplace */
+        0xffff,                /* src_mask */
+        0xffff,                /* dst_mask */
+        false),                /* pcrel_offset */
 
 };
 
 void
-_bfd_xcoff_rtype2howto (relent, internal)
+xcoff_rtype2howto (relent, internal)
      arelent *relent;
      struct internal_reloc *internal;
 {
-  relent->howto = xcoff_howto_table + internal->r_type;
-
-  /* Check for relocs we don't know of.  */
-  if (internal->r_type
-      >= sizeof (xcoff_howto_table) / sizeof (xcoff_howto_table[0]))
-    abort ();
-  if (internal->r_type != relent->howto->type)
+  if (internal->r_type > R_RBRC)
     abort ();
 
+  /* Default howto layout works most of the time */
+  relent->howto = &xcoff_howto_table[internal->r_type];
+  
+  /* Special case some 16 bit reoloc */
+  if (15 == (internal->r_size & 0x1f))
+    {
+      if (R_BA == internal->r_type) 
+       relent->howto = &xcoff_howto_table[0x1c];
+      else if (R_RBR == internal->r_type) 
+       relent->howto = &xcoff_howto_table[0x1d];
+      else if (R_RBA == internal->r_type) 
+       relent->howto = &xcoff_howto_table[0x1e];
+    }
+  
   /* The r_size field of an XCOFF reloc encodes the bitsize of the
      relocation, as well as indicating whether it is signed or not.
      Doublecheck that the relocation information gathered from the
@@ -894,14 +994,12 @@ _bfd_xcoff_rtype2howto (relent, internal)
      for R_REF relocs.  */
   if (relent->howto->dst_mask != 0
       && (relent->howto->bitsize
-         != ((unsigned int) internal->r_size & 0x3f) + 1))
+         != ((unsigned int) internal->r_size & 0x1f) + 1))
     abort ();
-#if 0
-  if ((internal->r_size & 0x80) != 0
-      ? (relent->howto->complain_on_overflow != complain_overflow_signed)
-      : (relent->howto->complain_on_overflow != complain_overflow_bitfield))
-    abort ();
-#endif
+
+  /* Put a meaningful value in addend */
+  relent->addend = (internal->r_size & 0x80) ? - internal->r_vaddr 
+    : internal->r_vaddr;
 }
 
 reloc_howto_type *
@@ -913,6 +1011,8 @@ _bfd_xcoff_reloc_type_lookup (abfd, code)
     {
     case BFD_RELOC_PPC_B26:
       return &xcoff_howto_table[0xa];
+    case BFD_RELOC_PPC_BA16:
+      return &xcoff_howto_table[0x1c];
     case BFD_RELOC_PPC_BA26:
       return &xcoff_howto_table[8];
     case BFD_RELOC_PPC_TOC16:
@@ -920,8 +1020,6 @@ _bfd_xcoff_reloc_type_lookup (abfd, code)
     case BFD_RELOC_32:
     case BFD_RELOC_CTOR:
       return &xcoff_howto_table[0];
-    case BFD_RELOC_64:
-      return &xcoff_howto_table[0x1c];
     default:
       return NULL;
     }
@@ -973,7 +1071,17 @@ _bfd_xcoff_reloc_type_lookup (abfd, code)
 /* XCOFF archives use this as a magic string.  Note that both strings
    have the same length.  */
 
+/* Set the magic for archive.  */
 
+boolean
+bfd_xcoff_ar_archive_set_magic (abfd, magic)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     char *magic ATTRIBUTE_UNUSED;
+{
+  /* Not supported yet.  */
+  return false;
+ /* bfd_xcoff_archive_set_magic (abfd, magic); */
+}
 
 /* Read in the armap of an XCOFF archive.  */
 
@@ -1389,7 +1497,7 @@ _bfd_xcoff_openr_next_archived_file (archive, last_file)
 /* Stat an element in an XCOFF archive.  */
 
 int
-_bfd_xcoff_generic_stat_arch_elt (abfd, s)
+_bfd_xcoff_stat_arch_elt (abfd, s)
      bfd *abfd;
      struct stat *s;
 {
@@ -1399,7 +1507,7 @@ _bfd_xcoff_generic_stat_arch_elt (abfd, s)
       return -1;
     }
 
-  if (! xcoff_big_format_p (abfd))
+  if (! xcoff_big_format_p (abfd->my_archive))
     {
       struct xcoff_ar_hdr *hdrp = arch_xhdr (abfd);
 
@@ -1462,7 +1570,7 @@ xcoff_write_armap_old (abfd, elength, map, orl_count, stridx)
   memset (&hdr, 0, sizeof hdr);
   sprintf (hdr.size, "%ld", (long) (4 + orl_count * 4 + stridx));
   sprintf (hdr.nextoff, "%d", 0);
-  memcpy (hdr.prevoff, xcoff_ardata (abfd)->memoff, 12);
+  memcpy (hdr.prevoff, xcoff_ardata (abfd)->memoff, XCOFFARMAG_ELEMENT_SIZE);
   sprintf (hdr.date, "%d", 0);
   sprintf (hdr.uid, "%d", 0);
   sprintf (hdr.gid, "%d", 0);
@@ -1531,123 +1639,105 @@ xcoff_write_armap_old (abfd, elength, map, orl_count, stridx)
   return true;
 }
 
-/* Write a single armap in the big format.  */
+static char buff20[XCOFFARMAGBIG_ELEMENT_SIZE + 1];
+#define FMT20  "%-20lld"
+#define FMT12  "%-12d"
+#define FMT12_OCTAL  "%-12o"
+#define FMT4  "%-4d"
+#define PRINT20(d, v) \
+  sprintf (buff20, FMT20, (long long)(v)), \
+  memcpy ((void *) (d), buff20, 20)
+
+#define PRINT12(d, v) \
+  sprintf (buff20, FMT12, (int)(v)), \
+  memcpy ((void *) (d), buff20, 12) 
+
+#define PRINT12_OCTAL(d, v) \
+  sprintf (buff20, FMT12_OCTAL, (unsigned int)(v)), \
+  memcpy ((void *) (d), buff20, 12)
+
+#define PRINT4(d, v) \
+  sprintf (buff20, FMT4, (int)(v)), \
+  memcpy ((void *) (d), buff20, 4) 
+
+#define READ20(d, v) \
+  buff20[20] = 0, \
+  memcpy (buff20, (d), 20), \
+  (v) = bfd_scan_vma (buff20, (const char **) NULL, 10)
 
 static boolean
-xcoff_write_one_armap_big (abfd, map, orl_count, orl_ccount, stridx, bits64,
-                          prevoff, nextoff)
+do_pad (abfd, number)
      bfd *abfd;
-     struct orl *map;
-     unsigned int orl_count;
-     unsigned int orl_ccount;
-     unsigned int stridx;
-     int bits64;
-     const char *prevoff;
-     char *nextoff;
+     unsigned int number;
 {
-  struct xcoff_ar_hdr_big hdr;
-  char *p;
-  unsigned char buf[4];
-  bfd *sub;
-  file_ptr fileoff;
-  const bfd_arch_info_type *arch_info = NULL;
-  bfd *object_bfd;
-  unsigned int i;
+  bfd_byte b = 0;
 
-  memset (&hdr, 0, sizeof hdr);
-  /* XXX This call actually should use %lld (at least on 32-bit
-     machines) since the fields's width is 20 and there numbers with
-     more than 32 bits can be represented.  */
-  sprintf (hdr.size, "%ld", (long) (4 + orl_ccount * 4 + stridx));
-  if (bits64)
-    {
-      sprintf (hdr.nextoff, "%d", 0);
-    }
-  else
-    {
-      /* Do explict cast to long to remove compiler warning.  */
-      sprintf (hdr.nextoff, "%ld", (strtol (prevoff, (char **) NULL, 10)
-                                   + (long) (4 + orl_ccount * 4 + stridx)));
-    }
+  /* Limit pad to <= 4096.  */
+  if (number > 4096)
+    return false;
 
-  memcpy (hdr.prevoff, prevoff, sizeof (hdr.prevoff));
-  sprintf (hdr.date, "%d", 0);
-  sprintf (hdr.uid, "%d", 0);
-  sprintf (hdr.gid, "%d", 0);
-  sprintf (hdr.mode, "%d", 0);
-  sprintf (hdr.namlen, "%d", 0);
+  while (number--)
+    if (bfd_bwrite (&b, (bfd_size_type) 1, abfd) != 1)
+      return false;
 
-  /* We need spaces, not null bytes, in the header.  */
-  for (p = (char *) &hdr; p < (char *) &hdr + SIZEOF_AR_HDR_BIG; p++)
-    if (*p == '\0')
-      *p = ' ';
+  return true;
+}
 
-  memcpy (nextoff, hdr.nextoff, sizeof (hdr.nextoff));
+static boolean
+do_copy (out_bfd, in_bfd)
+     bfd *out_bfd;
+     bfd *in_bfd;
+{
+  bfd_size_type remaining;
+  bfd_byte buffer[DEFAULT_BUFFERSIZE];
 
-  if ((bfd_bwrite ((PTR) &hdr, (bfd_size_type) SIZEOF_AR_HDR_BIG, abfd)
-       != SIZEOF_AR_HDR_BIG)
-      || (bfd_bwrite (XCOFFARFMAG, (bfd_size_type) SXCOFFARFMAG, abfd)
-         != SXCOFFARFMAG))
+  if (bfd_seek (in_bfd, (file_ptr) 0, SEEK_SET) != 0)
     return false;
 
-  H_PUT_32 (abfd, orl_ccount, buf);
-  if (bfd_bwrite (buf, (bfd_size_type) 4, abfd) != 4)
-    return false;
+  remaining = arelt_size (in_bfd);
 
-  sub = abfd->archive_head;
-  fileoff = SIZEOF_AR_FILE_HDR_BIG;
-  i = 0;
-  while (sub != NULL && i < orl_count)
+  while (remaining >= DEFAULT_BUFFERSIZE)
     {
-      size_t namlen;
-
-      if ((bfd_arch_bits_per_address (map[i].u.abfd) == 64) == bits64)
-       while (map[i].u.abfd == sub)
-         {
-           H_PUT_32 (abfd, fileoff, buf);
-           if (bfd_bwrite (buf, (bfd_size_type) 4, abfd) != 4)
-             return false;
-           i++;
-         }
-      else
-       while (map[i].u.abfd == sub)
-         i++;
+      if (bfd_bread (buffer, DEFAULT_BUFFERSIZE, in_bfd) != DEFAULT_BUFFERSIZE
+         || bfd_bwrite (buffer, DEFAULT_BUFFERSIZE, out_bfd) != DEFAULT_BUFFERSIZE)
+       return false;
 
-      namlen = strlen (normalize_filename (sub));
-      namlen = (namlen + 1) &~ (size_t) 1;
-      fileoff += (SIZEOF_AR_HDR_BIG
-                 + namlen
-                 + SXCOFFARFMAG
-                 + arelt_size (sub));
-      fileoff = (fileoff + 1) &~ 1;
-      sub = sub->next;
+      remaining -= DEFAULT_BUFFERSIZE;
     }
 
-  object_bfd = NULL;
-  for (i = 0; i < orl_count; i++)
+  if (remaining)
     {
-      const char *name;
-      size_t namlen;
-      bfd *ob = map[i].u.abfd;
-
-      if (ob != object_bfd)
-       arch_info = bfd_get_arch_info (ob);
-      if ((arch_info->bits_per_address == 64) != bits64)
-       continue;
-
-      name = *map[i].name;
-      namlen = strlen (name);
-      if (bfd_bwrite (name, (bfd_size_type) (namlen + 1), abfd) != namlen + 1)
+      if (bfd_bread (buffer, remaining, in_bfd) != remaining 
+         || bfd_bwrite (buffer, remaining, out_bfd) != remaining)
        return false;
     }
 
-  if ((stridx & 1) != 0)
+  return true;
+}
+
+static boolean 
+do_shared_object_padding (out_bfd, in_bfd, offset, ar_header_size)
+     bfd *out_bfd;
+     bfd *in_bfd;
+     ufile_ptr *offset;
+     int ar_header_size;
+{
+  if (bfd_check_format (in_bfd, bfd_object)
+      && bfd_get_flavour (in_bfd) == bfd_target_xcoff_flavour
+      && (in_bfd->flags & DYNAMIC) != 0)
     {
-      char b;
+      bfd_size_type pad = 0;
+      int text_align_power;
 
-      b = '\0';
-      if (bfd_bwrite (&b, (bfd_size_type) 1, abfd) != 1)
+      text_align_power = bfd_xcoff_text_align_power (in_bfd);
+
+      pad = 1 << text_align_power;
+      pad -= (*offset + ar_header_size) & (pad - 1);
+
+      if (! do_pad (out_bfd, pad))
        return false;
+
+      *offset += pad;
     }
 
   return true;
@@ -1661,55 +1751,278 @@ xcoff_write_armap_big (abfd, elength, map, orl_count, stridx)
      unsigned int orl_count;
      int stridx;
 {
-  unsigned int i;
-  unsigned int orl_count_32, orl_count_64;
-  unsigned int stridx_32, stridx_64;
+  struct xcoff_ar_file_hdr_big *fhdr;
+  bfd_vma i, sym_32, sym_64, str_32, str_64;
   const bfd_arch_info_type *arch_info = NULL;
-  bfd *object_bfd;
-
+  bfd *current_bfd;
+  size_t string_length;
+  ufile_ptr nextoff, prevoff;
+  
   /* First, we look through the symbols and work out which are
      from 32-bit objects and which from 64-bit ones.  */
-  orl_count_32 = 0;
-  orl_count_64 = 0;
-  stridx_32 = 0;
-  stridx_64 = 0;
-  object_bfd = NULL;
-  for (i = 0; i < orl_count; i++)
+  sym_32 = sym_64 = str_32 = str_64 = 0;
+
+  current_bfd = abfd->archive_head;
+  if (current_bfd != NULL)
+    arch_info = bfd_get_arch_info (current_bfd);
+    i = 0;
+    while (current_bfd != NULL && i < orl_count)
     {
-      bfd *ob = map[i].u.abfd;
-      unsigned int len;
-      if (ob != object_bfd)
-       arch_info = bfd_get_arch_info (ob);
-      len = strlen (*map[i].name) + 1;
-      if (arch_info->bits_per_address == 64)
+      while (map[i].u.abfd == current_bfd)
        {
-         orl_count_64++;
-         stridx_64 += len;
+         string_length = strlen (*map[i].name) + 1;
+
+         if (arch_info->bits_per_address == 64)
+           {
+             sym_64++;
+             str_64 += string_length;
+           }
+         else
+           {
+             sym_32++;
+             str_32 += string_length;
+           }
+         i++;
        }
+      current_bfd = current_bfd->next;
+      if (current_bfd != NULL)
+       arch_info = bfd_get_arch_info (current_bfd);
+    }
+
+  /* A quick sanity check... */
+  BFD_ASSERT (sym_64 + sym_32 == orl_count);
+  /* Explicit cast to int for compiler.  */
+  BFD_ASSERT ((int)(str_64 + str_32) == stridx);
+
+  fhdr = xcoff_ardata_big (abfd);
+
+  /* xcoff_write_archive_contents_big passes nextoff in symoff. */
+  READ20 (fhdr->memoff, prevoff);
+  READ20 (fhdr->symoff, nextoff);
+
+  BFD_ASSERT (nextoff == bfd_tell (abfd));
+
+  /* Write out the symbol table.  
+     Layout : 
+     
+     standard big archive header
+     0x0000                   ar_size   [0x14]
+     0x0014                   ar_nxtmem [0x14]
+     0x0028                   ar_prvmem [0x14]
+     0x003C                   ar_date   [0x0C]
+     0x0048                   ar_uid    [0x0C]
+     0x0054                   ar_gid    [0x0C]
+     0x0060                   ar_mod    [0x0C]
+     0x006C                   ar_namelen[0x04]
+     0x0070                   ar_fmag   [SXCOFFARFMAG]
+     
+     Symbol table 
+     0x0072                   num_syms  [0x08], binary
+     0x0078                   offsets   [0x08 * num_syms], binary
+     0x0086 + 0x08 * num_syms names     [??]
+     ??                       pad to even bytes.
+  */
+
+  if (sym_32) 
+    {
+      struct xcoff_ar_hdr_big *hdr;
+      bfd_byte *symbol_table;
+      bfd_byte *st;
+      file_ptr fileoff;
+
+      bfd_vma symbol_table_size = 
+       SIZEOF_AR_HDR_BIG
+       + SXCOFFARFMAG
+       + 8 
+       + 8 * sym_32 
+       + str_32 + (str_32 & 1);
+
+      symbol_table = NULL;
+      symbol_table = (bfd_byte *) bfd_zmalloc (symbol_table_size);
+      if (symbol_table == NULL)
+       return false;
+
+      hdr = (struct xcoff_ar_hdr_big *) symbol_table;
+       
+      PRINT20 (hdr->size, 8 + 8 * sym_32 + str_32 + (str_32 & 1));
+       
+      if (sym_64)
+       PRINT20 (hdr->nextoff, nextoff + symbol_table_size);
       else
+       PRINT20 (hdr->nextoff, 0);
+
+      PRINT20 (hdr->prevoff, prevoff);
+      PRINT12 (hdr->date, 0);
+      PRINT12 (hdr->uid, 0);
+      PRINT12 (hdr->gid, 0);
+      PRINT12 (hdr->mode, 0);
+      PRINT4 (hdr->namlen, 0) ;
+
+      st = symbol_table + SIZEOF_AR_HDR_BIG;
+      memcpy (st, XCOFFARFMAG, SXCOFFARFMAG);
+      st += SXCOFFARFMAG;
+
+      bfd_h_put_64 (abfd, sym_32, st);
+      st += 8;
+      
+      /* loop over the 32 bit offsets */
+      current_bfd = abfd->archive_head;
+      if (current_bfd != NULL)
+       arch_info = bfd_get_arch_info (current_bfd);
+      fileoff = SIZEOF_AR_FILE_HDR_BIG;
+      i = 0;
+      while (current_bfd != NULL && i < orl_count)
+       {
+         while (map[i].u.abfd == current_bfd)
+           {
+             if (arch_info->bits_per_address == 32)
+               {
+                 bfd_h_put_64 (abfd, fileoff, st);
+                 st += 8;
+               }
+             i++;
+           }
+         string_length = strlen (normalize_filename (current_bfd));
+         string_length += string_length & 1;
+         fileoff += (SIZEOF_AR_HDR_BIG
+                     + string_length
+                     + SXCOFFARFMAG
+                     + arelt_size (current_bfd));
+         fileoff += fileoff & 1;
+         current_bfd = current_bfd->next;
+         if (current_bfd != NULL)
+           arch_info = bfd_get_arch_info (current_bfd);
+       }
+
+      /* loop over the 32 bit symbol names */
+      current_bfd = abfd->archive_head;
+      if (current_bfd != NULL)
+       arch_info = bfd_get_arch_info (current_bfd);
+      i = 0;
+      while (current_bfd != NULL && i < orl_count)
        {
-         orl_count_32++;
-         stridx_32 += len;
+         while (map[i].u.abfd == current_bfd)
+           {
+             if (arch_info->bits_per_address == 32)
+               {
+                 string_length = sprintf (st, "%s", *map[i].name);
+                 st += string_length + 1;
+               }
+             i++;
+           }
+         current_bfd = current_bfd->next;
+         if (current_bfd != NULL)
+           arch_info = bfd_get_arch_info (current_bfd);
        }
-      object_bfd = ob;
+
+      bfd_bwrite (symbol_table, symbol_table_size, abfd);
+
+      free (symbol_table);
+      symbol_table = NULL;
+
+      prevoff = nextoff;
+      nextoff = nextoff + symbol_table_size;
     }
-  /* A quick sanity check... */
-  BFD_ASSERT (orl_count_64 + orl_count_32 == orl_count);
-  /* Explicit cast to int for compiler.  */
-  BFD_ASSERT ((int)(stridx_64 + stridx_32) == stridx);
+  else 
+    PRINT20 (fhdr->symoff, 0);
+  
+  if (sym_64) 
+    {
+      struct xcoff_ar_hdr_big *hdr;
+      bfd_byte *symbol_table;
+      bfd_byte *st;
+      file_ptr fileoff;
+
+      bfd_vma symbol_table_size = 
+       SIZEOF_AR_HDR_BIG
+       + SXCOFFARFMAG
+       + 8 
+       + 8 * sym_64 
+       + str_64 + (str_64 & 1);
+
+      symbol_table = NULL;
+      symbol_table = (bfd_byte *) bfd_zmalloc (symbol_table_size);
+      if (symbol_table == NULL)
+       return false;
 
-  /* Now write out each map.  */
-  if (! xcoff_write_one_armap_big (abfd, map, orl_count, orl_count_32,
-                                  stridx_32, false,
-                                  xcoff_ardata_big (abfd)->memoff,
-                                  xcoff_ardata_big (abfd)->symoff))
-    return false;
-  if (! xcoff_write_one_armap_big (abfd, map, orl_count, orl_count_64,
-                                  stridx_64, true,
-                                  xcoff_ardata_big (abfd)->symoff,
-                                  xcoff_ardata_big (abfd)->symoff64))
-    return false;
+      hdr = (struct xcoff_ar_hdr_big *) symbol_table;
+
+      PRINT20 (hdr->size, 8 + 8 * sym_64 + str_64 + (str_64 & 1));
+      PRINT20 (hdr->nextoff, 0);
+      PRINT20 (hdr->prevoff, prevoff);
+      PRINT12 (hdr->date, 0);
+      PRINT12 (hdr->uid, 0);
+      PRINT12 (hdr->gid, 0);
+      PRINT12 (hdr->mode, 0);
+      PRINT4 (hdr->namlen, 0);
+
+      st = symbol_table + SIZEOF_AR_HDR_BIG;
+      memcpy (st, XCOFFARFMAG, SXCOFFARFMAG);
+      st += SXCOFFARFMAG;
+
+      bfd_h_put_64 (abfd, sym_64, st);
+      st += 8;
+      
+      /* loop over the 64 bit offsets */
+      current_bfd = abfd->archive_head;
+      if (current_bfd != NULL)
+       arch_info = bfd_get_arch_info (current_bfd);
+      fileoff = SIZEOF_AR_FILE_HDR_BIG;
+      i = 0;
+      while (current_bfd != NULL && i < orl_count)
+       {
+         while (map[i].u.abfd == current_bfd)
+           {
+             if (arch_info->bits_per_address == 64)
+               {
+                 bfd_h_put_64 (abfd, fileoff, st);
+                 st += 8;
+               }
+             i++;
+           }
+         string_length = strlen (normalize_filename (current_bfd));
+         string_length += string_length & 1;
+         fileoff += (SIZEOF_AR_HDR_BIG
+                     + string_length
+                     + SXCOFFARFMAG
+                     + arelt_size (current_bfd));
+         fileoff += fileoff & 1;
+         current_bfd = current_bfd->next;
+         if (current_bfd != NULL)
+           arch_info = bfd_get_arch_info (current_bfd);
+       }
+
+      /* loop over the 64 bit symbol names */
+      current_bfd = abfd->archive_head;
+      if (current_bfd != NULL)
+       arch_info = bfd_get_arch_info (current_bfd);
+      i = 0;
+      while (current_bfd != NULL && i < orl_count)
+       {
+         while (map[i].u.abfd == current_bfd)
+           {
+             if (arch_info->bits_per_address == 64)
+               {
+                 string_length = sprintf (st, "%s", *map[i].name);
+                 st += string_length + 1;
+               }
+             i++;
+           }
+         current_bfd = current_bfd->next;
+         if (current_bfd != NULL)
+           arch_info = bfd_get_arch_info (current_bfd);
+       }
+
+      bfd_bwrite (symbol_table, symbol_table_size, abfd);
+
+      free (symbol_table);
+      symbol_table = NULL;
 
+      PRINT20 (fhdr->symoff64, nextoff);
+    }
+  else 
+    PRINT20 (fhdr->symoff64, 0);
+  
   return true;
 }
 
@@ -1746,7 +2059,7 @@ xcoff_write_archive_contents_old (abfd)
   struct xcoff_ar_hdr ahdr;
   bfd_size_type size;
   char *p;
-  char decbuf[13];
+  char decbuf[XCOFFARMAG_ELEMENT_SIZE + 1];
 
   memset (&fhdr, 0, sizeof fhdr);
   strncpy (fhdr.magic, XCOFFARMAG, SXCOFFARMAG);
@@ -1857,28 +2170,12 @@ xcoff_write_archive_contents_old (abfd)
 
       if (bfd_seek (sub, (file_ptr) 0, SEEK_SET) != 0)
        return false;
-      while (remaining != 0)
-       {
-         bfd_size_type amt;
-         bfd_byte buffer[DEFAULT_BUFFERSIZE];
-
-         amt = sizeof buffer;
-         if (amt > remaining)
-           amt = remaining;
-         if (bfd_bread (buffer, amt, sub) != amt
-             || bfd_bwrite (buffer, amt, abfd) != amt)
-           return false;
-         remaining -= amt;
-       }
-
-      if ((size & 1) != 0)
-       {
-         bfd_byte b;
 
-         b = '\0';
-         if (bfd_bwrite (&b, (bfd_size_type) 1, abfd) != 1)
-           return false;
-       }
+      if (! do_copy (abfd, sub))
+       return false;
+      
+      if (! do_pad (abfd, size & 1))
+       return false;
     }
 
   sprintf (fhdr.lastmemoff, "%ld", (long) prevoff);
@@ -1889,7 +2186,9 @@ xcoff_write_archive_contents_old (abfd)
   sprintf (fhdr.memoff, "%ld", (long) nextoff);
 
   memset (&ahdr, 0, sizeof ahdr);
-  sprintf (ahdr.size, "%ld", (long) (12 + count * 12 + total_namlen));
+  sprintf (ahdr.size, "%ld", (long) (XCOFFARMAG_ELEMENT_SIZE + 
+                                    count * XCOFFARMAG_ELEMENT_SIZE + 
+                                    total_namlen));
   sprintf (ahdr.prevoff, "%ld", (long) prevoff);
   sprintf (ahdr.date, "%d", 0);
   sprintf (ahdr.uid, "%d", 0);
@@ -1898,8 +2197,8 @@ xcoff_write_archive_contents_old (abfd)
   sprintf (ahdr.namlen, "%d", 0);
 
   size = (SIZEOF_AR_HDR
-         + 12
-         + count * 12
+         + XCOFFARMAG_ELEMENT_SIZE
+         + count * XCOFFARMAG_ELEMENT_SIZE
          + total_namlen
          + SXCOFFARFMAG);
 
@@ -1923,12 +2222,14 @@ xcoff_write_archive_contents_old (abfd)
     return false;
 
   sprintf (decbuf, "%-12ld", (long) count);
-  if (bfd_bwrite ((PTR) decbuf, (bfd_size_type) 12, abfd) != 12)
+  if (bfd_bwrite ((PTR) decbuf, (bfd_size_type) XCOFFARMAG_ELEMENT_SIZE, abfd)
+      != XCOFFARMAG_ELEMENT_SIZE)
     return false;
   for (i = 0; i < (size_t) count; i++)
     {
       sprintf (decbuf, "%-12ld", (long) offsets[i]);
-      if (bfd_bwrite ((PTR) decbuf, (bfd_size_type) 12, abfd) != 12)
+      if (bfd_bwrite ((PTR) decbuf, (bfd_size_type) XCOFFARMAG_ELEMENT_SIZE, 
+                     abfd) != XCOFFARMAG_ELEMENT_SIZE)
        return false;
     }
   for (sub = abfd->archive_head; sub != NULL; sub = sub->next)
@@ -1941,17 +2242,11 @@ xcoff_write_archive_contents_old (abfd)
       if (bfd_bwrite ((PTR) name, namlen + 1, abfd) != namlen + 1)
        return false;
     }
-  if ((size & 1) != 0)
-    {
-      bfd_byte b;
 
-      b = '\0';
-      if (bfd_bwrite ((PTR) &b, (bfd_size_type) 1, abfd) != 1)
-       return false;
-    }
+  if (! do_pad (abfd, size & 1))
+    return false;
 
   /* Write out the armap, if appropriate.  */
-
   if (! makemap || ! hasobjects)
     sprintf (fhdr.symoff, "%d", 0);
   else
@@ -1989,54 +2284,58 @@ xcoff_write_archive_contents_big (abfd)
   boolean makemap;
   boolean hasobjects;
   ufile_ptr prevoff, nextoff;
-  bfd *sub;
+  bfd *current_bfd;
   size_t i;
-  struct xcoff_ar_hdr_big ahdr;
+  struct xcoff_ar_hdr_big *hdr, ahdr;
   bfd_size_type size;
-  char *p;
-  char decbuf[13];
-
-  memset (&fhdr, 0, sizeof fhdr);
-  strncpy (fhdr.magic, XCOFFARMAGBIG, SXCOFFARMAG);
-  sprintf (fhdr.firstmemoff, "%d", SIZEOF_AR_FILE_HDR_BIG);
-  sprintf (fhdr.freeoff, "%d", 0);
+  bfd_byte *member_table, *mt;
+  bfd_vma member_table_size;
 
-  count = 0;
-  total_namlen = 0;
-  for (sub = abfd->archive_head; sub != NULL; sub = sub->next)
-    {
-      ++count;
-      total_namlen += strlen (normalize_filename (sub)) + 1;
-    }
-  offsets = (file_ptr *) bfd_alloc (abfd, count * sizeof (file_ptr));
-  if (offsets == NULL)
-    return false;
+  memset (&fhdr, 0, SIZEOF_AR_FILE_HDR_BIG);
+  memcpy (fhdr.magic, XCOFFARMAGBIG, SXCOFFARMAG);
 
   if (bfd_seek (abfd, (file_ptr) SIZEOF_AR_FILE_HDR_BIG, SEEK_SET) != 0)
     return false;
-
+  
+  /* Calculate count and total_namlen.  */
   makemap = bfd_has_map (abfd);
   hasobjects = false;
+  for (current_bfd = abfd->archive_head, count = 0, total_namlen = 0; 
+       current_bfd != NULL; 
+       current_bfd = current_bfd->next, count++)
+    {
+      total_namlen += strlen (normalize_filename (current_bfd)) + 1;
+
+      if (makemap
+         && ! hasobjects
+         && bfd_check_format (current_bfd, bfd_object))
+       hasobjects = true;
+    }
+
+  offsets = NULL;
+  if (count)
+    {
+      offsets = (file_ptr *) bfd_malloc (count * sizeof (file_ptr));
+      if (offsets == NULL)
+       return false;
+    }
+
   prevoff = 0;
   nextoff = SIZEOF_AR_FILE_HDR_BIG;
-  for (sub = abfd->archive_head, i = 0; sub != NULL; sub = sub->next, i++)
+  for (current_bfd = abfd->archive_head, i = 0; 
+       current_bfd != NULL; 
+       current_bfd = current_bfd->next, i++)
     {
       const char *name;
       bfd_size_type namlen;
       struct xcoff_ar_hdr_big *ahdrp;
       bfd_size_type remaining;
 
-      if (makemap && ! hasobjects)
-       {
-         if (bfd_check_format (sub, bfd_object))
-           hasobjects = true;
-       }
-
-      name = normalize_filename (sub);
+      name = normalize_filename (current_bfd);
       namlen = strlen (name);
 
-      if (sub->arelt_data != NULL)
-       ahdrp = arch_xhdr_big (sub);
+      if (current_bfd->arelt_data != NULL)
+       ahdrp = arch_xhdr_big (current_bfd);
       else
        ahdrp = NULL;
 
@@ -2044,47 +2343,41 @@ xcoff_write_archive_contents_big (abfd)
        {
          struct stat s;
 
-         memset (&ahdr, 0, sizeof ahdr);
          ahdrp = &ahdr;
          /* XXX This should actually be a call to stat64 (at least on
-            32-bit machines).  */
-         if (stat (bfd_get_filename (sub), &s) != 0)
+            32-bit machines).  
+            XXX This call will fail if the original object is not found.  */
+         if (stat (bfd_get_filename (current_bfd), &s) != 0)
            {
              bfd_set_error (bfd_error_system_call);
              return false;
            }
 
-         /* XXX This call actually should use %lld (at least on 32-bit
-            machines) since the fields's width is 20 and there numbers with
-            more than 32 bits can be represented.  */
-         sprintf (ahdrp->size, "%ld", (long) s.st_size);
-         sprintf (ahdrp->date, "%ld", (long) s.st_mtime);
-         sprintf (ahdrp->uid, "%ld", (long) s.st_uid);
-         sprintf (ahdrp->gid, "%ld", (long) s.st_gid);
-         sprintf (ahdrp->mode, "%o", (unsigned int) s.st_mode);
+         PRINT20 (ahdrp->size, s.st_size);
+         PRINT12 (ahdrp->date, s.st_mtime);
+         PRINT12 (ahdrp->uid,  s.st_uid);
+         PRINT12 (ahdrp->gid,  s.st_gid);
+         PRINT12_OCTAL (ahdrp->mode, s.st_mode);
 
-         if (sub->arelt_data == NULL)
+         if (current_bfd->arelt_data == NULL)
            {
              size = sizeof (struct areltdata);
-             sub->arelt_data = bfd_alloc (sub, size);
-             if (sub->arelt_data == NULL)
+             current_bfd->arelt_data = bfd_alloc (current_bfd, size);
+             if (current_bfd->arelt_data == NULL)
                return false;
            }
 
-         arch_eltdata (sub)->parsed_size = s.st_size;
+         arch_eltdata (current_bfd)->parsed_size = s.st_size;
        }
 
-      /* XXX These calls actually should use %lld (at least on 32-bit
-        machines) since the fields's width is 20 and there numbers with
-        more than 32 bits can be represented.  */
-      sprintf (ahdrp->prevoff, "%ld", (long) prevoff);
-      sprintf (ahdrp->namlen, "%ld", (long) namlen);
+      PRINT20 (ahdrp->prevoff, prevoff);
+      PRINT4 (ahdrp->namlen, namlen);
 
       /* If the length of the name is odd, we write out the null byte
          after the name as well.  */
       namlen = (namlen + 1) &~ (bfd_size_type) 1;
 
-      remaining = arelt_size (sub);
+      remaining = arelt_size (current_bfd);
       size = (SIZEOF_AR_HDR_BIG
              + namlen
              + SXCOFFARFMAG
@@ -2092,143 +2385,146 @@ xcoff_write_archive_contents_big (abfd)
 
       BFD_ASSERT (nextoff == bfd_tell (abfd));
 
+      /* Check for xcoff shared objects.
+        Their text section needs to be aligned wrt the archive file position.
+        This requires extra padding before the archive header.  */
+      if (! do_shared_object_padding (abfd, current_bfd, & nextoff,
+                                     SIZEOF_AR_HDR_BIG + namlen 
+                                     + SXCOFFARFMAG))
+       return false;
+
       offsets[i] = nextoff;
 
       prevoff = nextoff;
       nextoff += size + (size & 1);
 
-      sprintf (ahdrp->nextoff, "%ld", (long) nextoff);
-
-      /* We need spaces, not null bytes, in the header.  */
-      for (p = (char *) ahdrp; p < (char *) ahdrp + SIZEOF_AR_HDR_BIG; p++)
-       if (*p == '\0')
-         *p = ' ';
+      PRINT20 (ahdrp->nextoff, nextoff);
 
       if ((bfd_bwrite ((PTR) ahdrp, (bfd_size_type) SIZEOF_AR_HDR_BIG, abfd)
           != SIZEOF_AR_HDR_BIG)
          || bfd_bwrite ((PTR) name, (bfd_size_type) namlen, abfd) != namlen
-         || (bfd_bwrite ((PTR) XCOFFARFMAG, (bfd_size_type) SXCOFFARFMAG, abfd)
-             != SXCOFFARFMAG))
+         || (bfd_bwrite ((PTR) XCOFFARFMAG, (bfd_size_type) SXCOFFARFMAG, 
+                         abfd) != SXCOFFARFMAG))
        return false;
 
-      if (bfd_seek (sub, (file_ptr) 0, SEEK_SET) != 0)
+      if (bfd_seek (current_bfd, (file_ptr) 0, SEEK_SET) != 0)
        return false;
-      while (remaining != 0)
-       {
-         bfd_size_type amt;
-         bfd_byte buffer[DEFAULT_BUFFERSIZE];
-
-         amt = sizeof buffer;
-         if (amt > remaining)
-           amt = remaining;
-         if (bfd_bread (buffer, amt, sub) != amt
-             || bfd_bwrite (buffer, amt, abfd) != amt)
-           return false;
-         remaining -= amt;
-       }
-
-      if ((size & 1) != 0)
-       {
-         bfd_byte b;
 
-         b = '\0';
-         if (bfd_bwrite (&b, (bfd_size_type) 1, abfd) != 1)
-           return false;
-       }
+      if (! do_copy (abfd, current_bfd))
+       return false;
+  
+      if (! do_pad (abfd, size & 1))
+       return false;
     }
 
-  /* XXX This call actually should use %lld (at least on 32-bit
-     machines) since the fields's width is 20 and there numbers with
-     more than 32 bits can be represented.  */
-  sprintf (fhdr.lastmemoff, "%ld", (long) prevoff);
+  if (count)
+    {
+      PRINT20 (fhdr.firstmemoff, offsets[0]);
+      PRINT20 (fhdr.lastmemoff, prevoff);
+    }
 
-  /* Write out the member table.  */
+  /* Write out the member table.  
+     Layout : 
+
+     standard big archive header
+     0x0000                   ar_size   [0x14]
+     0x0014                   ar_nxtmem [0x14]
+     0x0028                   ar_prvmem [0x14]
+     0x003C                   ar_date   [0x0C]
+     0x0048                   ar_uid    [0x0C]
+     0x0054                   ar_gid    [0x0C]
+     0x0060                   ar_mod    [0x0C]
+     0x006C                   ar_namelen[0x04]
+     0x0070                   ar_fmag   [0x02]
+
+     Member table 
+     0x0072                   count     [0x14]
+     0x0086                   offsets   [0x14 * counts]
+     0x0086 + 0x14 * counts   names     [??]
+     ??                       pad to even bytes.
+   */
 
   BFD_ASSERT (nextoff == bfd_tell (abfd));
-  /* XXX This call actually should use %lld (at least on 32-bit
-     machines) since the fields's width is 20 and there numbers with
-     more than 32 bits can be represented.  */
-  sprintf (fhdr.memoff, "%ld", (long) nextoff);
 
-  memset (&ahdr, 0, sizeof ahdr);
-  /* XXX The next two calls actually should use %lld (at least on 32-bit
-     machines) since the fields's width is 20 and there numbers with
-     more than 32 bits can be represented.  */
-  sprintf (ahdr.size, "%ld", (long) (12 + count * 12 + total_namlen));
-  sprintf (ahdr.prevoff, "%ld", (long) prevoff);
-  sprintf (ahdr.date, "%d", 0);
-  sprintf (ahdr.uid, "%d", 0);
-  sprintf (ahdr.gid, "%d", 0);
-  sprintf (ahdr.mode, "%d", 0);
-  sprintf (ahdr.namlen, "%d", 0);
+  member_table_size = (SIZEOF_AR_HDR_BIG
+                      + SXCOFFARFMAG
+                      + XCOFFARMAGBIG_ELEMENT_SIZE
+                      + count * XCOFFARMAGBIG_ELEMENT_SIZE
+                      + total_namlen);
 
-  size = (SIZEOF_AR_HDR_BIG
-         + 12
-         + count * 12
-         + total_namlen
-         + SXCOFFARFMAG);
+  member_table_size += member_table_size & 1;
+  member_table = NULL;
+  member_table = (bfd_byte *) bfd_zmalloc (member_table_size);
+  if (member_table == NULL)
+    return false;
 
-  prevoff = nextoff;
-  nextoff += size + (size & 1);
+  hdr = (struct xcoff_ar_hdr_big *) member_table;
 
-  if (makemap && hasobjects)
-    /* XXX This call actually should use %lld (at least on 32-bit
-       machines) since the fields's width is 20 and there numbers with
-       more than 32 bits can be represented.  */
-    sprintf (ahdr.nextoff, "%ld", (long) nextoff);
+  PRINT20 (hdr->size, (XCOFFARMAGBIG_ELEMENT_SIZE + 
+                      count * XCOFFARMAGBIG_ELEMENT_SIZE + 
+                      total_namlen + (total_namlen & 1)));
+  if (makemap && hasobjects) 
+    PRINT20 (hdr->nextoff, nextoff + member_table_size);
   else
-    sprintf (ahdr.nextoff, "%d", 0);
-
-  /* We need spaces, not null bytes, in the header.  */
-  for (p = (char *) &ahdr; p < (char *) &ahdr + SIZEOF_AR_HDR_BIG; p++)
-    if (*p == '\0')
-      *p = ' ';
-
-  if ((bfd_bwrite ((PTR) &ahdr, (bfd_size_type) SIZEOF_AR_HDR_BIG, abfd)
-       != SIZEOF_AR_HDR_BIG)
-      || (bfd_bwrite ((PTR) XCOFFARFMAG, (bfd_size_type) SXCOFFARFMAG, abfd)
-         != SXCOFFARFMAG))
-    return false;
+    PRINT20 (hdr->nextoff, 0);
+  PRINT20 (hdr->prevoff, prevoff);
+  PRINT12 (hdr->date, 0);
+  PRINT12 (hdr->uid, 0);
+  PRINT12 (hdr->gid, 0);
+  PRINT12 (hdr->mode, 0);
+  PRINT4 (hdr->namlen, 0);
+  
+  mt = member_table + SIZEOF_AR_HDR_BIG;
+  memcpy (mt, XCOFFARFMAG, SXCOFFARFMAG);
+  mt += SXCOFFARFMAG;
 
-  sprintf (decbuf, "%-12ld", (long) count);
-  if (bfd_bwrite ((PTR) decbuf, (bfd_size_type) 12, abfd) != 12)
-    return false;
+  PRINT20 (mt, count);
+  mt += XCOFFARMAGBIG_ELEMENT_SIZE;
   for (i = 0; i < (size_t) count; i++)
     {
-      sprintf (decbuf, "%-12ld", (long) offsets[i]);
-      if (bfd_bwrite ((PTR) decbuf, (bfd_size_type) 12, abfd) != 12)
-       return false;
+      PRINT20 (mt, offsets[i]);
+      mt += XCOFFARMAGBIG_ELEMENT_SIZE;
     }
-  for (sub = abfd->archive_head; sub != NULL; sub = sub->next)
+
+  if (count) 
+    {
+      free (offsets);
+      offsets = NULL;
+    }
+
+  for (current_bfd = abfd->archive_head; current_bfd != NULL; 
+       current_bfd = current_bfd->next)
     {
       const char *name;
       size_t namlen;
 
-      name = normalize_filename (sub);
-      namlen = strlen (name);
-      if (bfd_bwrite ((PTR) name, (bfd_size_type) (namlen + 1), abfd)
-         != namlen + 1)
-       return false;
+      name = normalize_filename (current_bfd);
+      namlen = sprintf(mt, "%s", name);
+      mt += namlen + 1;
     }
-  if ((size & 1) != 0)
-    {
-      bfd_byte b;
+  
+  if (bfd_bwrite (member_table, member_table_size, abfd) != member_table_size)
+    return false;
 
-      b = '\0';
-      if (bfd_bwrite ((PTR) &b, (bfd_size_type) 1, abfd) != 1)
-       return false;
-    }
+  free (member_table);
+  member_table = NULL;
+
+  PRINT20 (fhdr.memoff, nextoff);
+
+  prevoff = nextoff;
+  nextoff += member_table_size;
 
   /* Write out the armap, if appropriate.  */
 
-  if (! makemap || ! hasobjects)
-    sprintf (fhdr.symoff, "%d", 0);
+  if (! makemap || ! hasobjects) 
+    PRINT20 (fhdr.symoff, 0);
   else
     {
       BFD_ASSERT (nextoff == bfd_tell (abfd));
-      /* XXX This call actually should use %lld (at least on 32-bit
-        machines) since the fields's width is 20 and there numbers with
-        more than 32 bits can be represented.  */
+
+      /* Save nextoff in fhdr.symoff so the armap routine can use it.  */
+      PRINT20 (fhdr.symoff, nextoff);
+      
       bfd_ardata (abfd)->tdata = (PTR) &fhdr;
       if (! _bfd_compute_and_write_armap (abfd, 0))
        return false;
@@ -2236,16 +2532,11 @@ xcoff_write_archive_contents_big (abfd)
 
   /* Write out the archive file header.  */
 
-  /* We need spaces, not null bytes, in the header.  */
-  for (p = (char *) &fhdr; p < (char *) &fhdr + SIZEOF_AR_FILE_HDR_BIG; p++)
-    if (*p == '\0')
-      *p = ' ';
-
   if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0
-      || (bfd_bwrite ((PTR) &fhdr, (bfd_size_type) SIZEOF_AR_FILE_HDR_BIG, abfd)
-         != SIZEOF_AR_FILE_HDR_BIG))
+      || (bfd_bwrite ((PTR) &fhdr, (bfd_size_type) SIZEOF_AR_FILE_HDR_BIG, 
+                     abfd) != SIZEOF_AR_FILE_HDR_BIG))
     return false;
-
+  
   return true;
 }
 
@@ -2373,6 +2664,40 @@ xcoff_swap_ldsym_out (abfd, src, d)
   bfd_put_32 (abfd, src->l_parm, dst->l_parm);
 }
 
+static void
+xcoff_swap_reloc_in (abfd, s, d)
+     bfd *abfd;
+     PTR s;
+     PTR d;
+{
+  struct external_reloc *src = (struct external_reloc *) s;
+  struct internal_reloc *dst = (struct internal_reloc *) d;
+
+  memset (dst, 0, sizeof (struct internal_reloc));
+
+  dst->r_vaddr = bfd_get_32 (abfd, src->r_vaddr);
+  dst->r_symndx = bfd_get_32 (abfd, src->r_symndx);
+  dst->r_size = bfd_get_8 (abfd, src->r_size);
+  dst->r_type = bfd_get_8 (abfd, src->r_type);
+}
+
+static unsigned int
+xcoff_swap_reloc_out (abfd, s, d)
+     bfd *abfd;
+     PTR s;
+     PTR d;
+{
+  struct internal_reloc *src = (struct internal_reloc *) s;
+  struct external_reloc *dst = (struct external_reloc *) d;
+
+  bfd_put_32 (abfd, src->r_vaddr, dst->r_vaddr);
+  bfd_put_32 (abfd, src->r_symndx, dst->r_symndx);
+  bfd_put_8 (abfd, src->r_type, dst->r_type);
+  bfd_put_8 (abfd, src->r_size, dst->r_size);
+
+  return bfd_coff_relsz (abfd);
+}
+
 /* Swap in the ldrel structure.  */
 
 static void
@@ -2406,12 +2731,577 @@ xcoff_swap_ldrel_out (abfd, src, d)
 }
 \f
 
+boolean 
+xcoff_reloc_type_noop (input_bfd, input_section, output_bfd, rel, sym, howto, 
+                      val, addend, relocation, contents)
+     bfd *input_bfd ATTRIBUTE_UNUSED;
+     asection *input_section ATTRIBUTE_UNUSED;
+     bfd *output_bfd ATTRIBUTE_UNUSED;
+     struct internal_reloc *rel ATTRIBUTE_UNUSED;
+     struct internal_syment *sym ATTRIBUTE_UNUSED;
+     struct reloc_howto_struct *howto ATTRIBUTE_UNUSED;
+     bfd_vma val ATTRIBUTE_UNUSED;
+     bfd_vma addend ATTRIBUTE_UNUSED;
+     bfd_vma *relocation ATTRIBUTE_UNUSED;
+     bfd_byte *contents ATTRIBUTE_UNUSED;
+{
+  return true;
+}
+
+boolean 
+xcoff_reloc_type_fail (input_bfd, input_section, output_bfd, rel, sym, howto, 
+                      val, addend, relocation, contents)
+     bfd *input_bfd;
+     asection *input_section ATTRIBUTE_UNUSED;
+     bfd *output_bfd ATTRIBUTE_UNUSED;
+     struct internal_reloc *rel;
+     struct internal_syment *sym ATTRIBUTE_UNUSED;
+     struct reloc_howto_struct *howto ATTRIBUTE_UNUSED;
+     bfd_vma val ATTRIBUTE_UNUSED;
+     bfd_vma addend ATTRIBUTE_UNUSED;
+     bfd_vma *relocation ATTRIBUTE_UNUSED;
+     bfd_byte *contents ATTRIBUTE_UNUSED;
+{
+  (*_bfd_error_handler)
+    (_("%s: unsupported relocation type 0x%02x"),
+     bfd_get_filename (input_bfd), (unsigned int) rel->r_type);
+  bfd_set_error (bfd_error_bad_value);
+  return false;
+}
+
+boolean 
+xcoff_reloc_type_pos (input_bfd, input_section, output_bfd, rel, sym, howto, 
+                     val, addend, relocation, contents)
+     bfd *input_bfd ATTRIBUTE_UNUSED;
+     asection *input_section ATTRIBUTE_UNUSED;
+     bfd *output_bfd ATTRIBUTE_UNUSED;
+     struct internal_reloc *rel ATTRIBUTE_UNUSED;
+     struct internal_syment *sym ATTRIBUTE_UNUSED;
+     struct reloc_howto_struct *howto ATTRIBUTE_UNUSED;
+     bfd_vma val;
+     bfd_vma addend;
+     bfd_vma *relocation;
+     bfd_byte *contents ATTRIBUTE_UNUSED;
+{
+  *relocation = val + addend;
+  return true;
+}
+
+boolean 
+xcoff_reloc_type_neg (input_bfd, input_section, output_bfd, rel, sym, howto, 
+                     val, addend, relocation, contents)
+     bfd *input_bfd ATTRIBUTE_UNUSED;
+     asection *input_section ATTRIBUTE_UNUSED;
+     bfd *output_bfd ATTRIBUTE_UNUSED;
+     struct internal_reloc *rel ATTRIBUTE_UNUSED;
+     struct internal_syment *sym ATTRIBUTE_UNUSED;
+     struct reloc_howto_struct *howto ATTRIBUTE_UNUSED;
+     bfd_vma val;
+     bfd_vma addend;
+     bfd_vma *relocation;
+     bfd_byte *contents ATTRIBUTE_UNUSED;
+{
+  *relocation = addend - val;
+  return true;
+}
+
+boolean 
+xcoff_reloc_type_rel (input_bfd, input_section, output_bfd, rel, sym, howto, 
+                     val, addend, relocation, contents)
+     bfd *input_bfd ATTRIBUTE_UNUSED;
+     asection *input_section;
+     bfd *output_bfd ATTRIBUTE_UNUSED;
+     struct internal_reloc *rel ATTRIBUTE_UNUSED;
+     struct internal_syment *sym ATTRIBUTE_UNUSED;
+     struct reloc_howto_struct *howto;
+     bfd_vma val;
+     bfd_vma addend;
+     bfd_vma *relocation;
+     bfd_byte *contents ATTRIBUTE_UNUSED;
+{
+  howto->pc_relative = true;
+
+  /* A PC relative reloc includes the section address.  */
+  addend += input_section->vma;
+
+  *relocation = val + addend;
+  *relocation -= (input_section->output_section->vma + 
+                 input_section->output_offset);
+  return true;
+}
+
+boolean 
+xcoff_reloc_type_toc (input_bfd, input_section, output_bfd, rel, sym, howto, 
+                     val, addend, relocation, contents)
+     bfd *input_bfd;
+     asection *input_section ATTRIBUTE_UNUSED;
+     bfd *output_bfd;
+     struct internal_reloc *rel;
+     struct internal_syment *sym;
+     struct reloc_howto_struct *howto ATTRIBUTE_UNUSED;
+     bfd_vma val;
+     bfd_vma addend ATTRIBUTE_UNUSED;
+     bfd_vma *relocation;
+     bfd_byte *contents ATTRIBUTE_UNUSED;
+{
+  struct xcoff_link_hash_entry *h;
+
+  if (0 > rel->r_symndx) 
+    return false;
+
+  h = obj_xcoff_sym_hashes (input_bfd)[rel->r_symndx];
+
+  if (h != NULL && h->smclas != XMC_TD)
+    {
+      if (h->toc_section == NULL)
+       {
+         (*_bfd_error_handler)
+           (_("%s: TOC reloc at 0x%x to symbol `%s' with no TOC entry"),
+            bfd_get_filename (input_bfd), rel->r_vaddr,
+            h->root.root.string);
+         bfd_set_error (bfd_error_bad_value);
+         return false;
+       }
+      
+      BFD_ASSERT ((h->flags & XCOFF_SET_TOC) == 0);
+      val = (h->toc_section->output_section->vma
+             + h->toc_section->output_offset);
+    }
+  
+  *relocation = ((val - xcoff_data (output_bfd)->toc) - 
+                (sym->n_value - xcoff_data (input_bfd)->toc));
+  return true;
+}
+
+boolean 
+xcoff_reloc_type_ba (input_bfd, input_section, output_bfd, rel, sym, howto, 
+                    val, addend, relocation, contents)
+     bfd *input_bfd ATTRIBUTE_UNUSED;
+     asection *input_section ATTRIBUTE_UNUSED;
+     bfd *output_bfd ATTRIBUTE_UNUSED;
+     struct internal_reloc *rel ATTRIBUTE_UNUSED;
+     struct internal_syment *sym ATTRIBUTE_UNUSED;
+     struct reloc_howto_struct *howto;
+     bfd_vma val;
+     bfd_vma addend;
+     bfd_vma *relocation;
+     bfd_byte *contents ATTRIBUTE_UNUSED;
+{
+  howto->src_mask &= ~3;
+  howto->dst_mask = howto->src_mask;
+
+  *relocation = val + addend;
+
+  return true;
+}
+
+static boolean 
+xcoff_reloc_type_br (input_bfd, input_section, output_bfd, rel, sym, howto, 
+                    val, addend, relocation, contents)
+     bfd *input_bfd;
+     asection *input_section;
+     bfd *output_bfd ATTRIBUTE_UNUSED;
+     struct internal_reloc *rel;
+     struct internal_syment *sym ATTRIBUTE_UNUSED;
+     struct reloc_howto_struct *howto;
+     bfd_vma val;
+     bfd_vma addend;
+     bfd_vma *relocation;
+     bfd_byte *contents;
+{
+  struct xcoff_link_hash_entry *h;
+
+  if (0 > rel->r_symndx) 
+    return false;
+
+  h = obj_xcoff_sym_hashes (input_bfd)[rel->r_symndx];
+
+  /* If we see an R_BR or R_RBR reloc which is jumping to global
+     linkage code, and it is followed by an appropriate cror nop
+     instruction, we replace the cror with lwz r2,20(r1).  This
+     restores the TOC after the glink code.  Contrariwise, if the
+     call is followed by a lwz r2,20(r1), but the call is not
+     going to global linkage code, we can replace the load with a
+     cror.  */
+  if (NULL != h 
+      && bfd_link_hash_defined == h->root.type 
+      && (rel->r_vaddr - input_section->vma + 8 <= 
+         input_section->_cooked_size)) 
+    {
+      bfd_byte *pnext;
+      unsigned long next;
+      
+      pnext = contents + (rel->r_vaddr - input_section->vma) + 4;
+      next = bfd_get_32 (input_bfd, pnext);
+      
+      /* The _ptrgl function is magic.  It is used by the AIX
+        compiler to call a function through a pointer.  */
+      if (h->smclas == XMC_GL || strcmp (h->root.root.string, "._ptrgl") == 0)
+       {
+         if (next == 0x4def7b82                        /* cror 15,15,15 */
+             || next == 0x4ffffb82                     /* cror 31,31,31 */
+             || next == 0x60000000)                    /* ori r0,r0,0 */
+           bfd_put_32 (input_bfd, 0x80410014, pnext);  /* lwz r1,20(r1) */
+         
+       } else 
+         {
+           if (next == 0x80410014)                      /* lwz r1,20(r1) */
+             bfd_put_32 (input_bfd, 0x60000000, pnext); /* ori r0,r0,0 */
+         }
+    } 
+  else if (NULL != h && bfd_link_hash_undefined == h->root.type) 
+    {
+      /* Normally, this relocation is against a defined symbol.  In the
+        case where this is a partial link and the output section offset
+        is greater than 2^25, the linker will return an invalid error 
+        message that the relocation has been truncated.  Yes it has been
+        truncated but no it not important.  For this case, disable the 
+        overflow checking. */
+      
+      howto->complain_on_overflow = complain_overflow_dont;
+    }
+  
+  howto->pc_relative = true;
+  howto->src_mask &= ~3;
+  howto->dst_mask = howto->src_mask;
+
+  /* A PC relative reloc includes the section address.  */
+  addend += input_section->vma;
+  
+  *relocation = val + addend;
+  *relocation -= (input_section->output_section->vma + 
+                 input_section->output_offset);
+  return true;
+}
+
+boolean 
+xcoff_reloc_type_crel (input_bfd, input_section, output_bfd, rel, sym, howto, 
+                      val, addend, relocation, contents)
+     bfd *input_bfd ATTRIBUTE_UNUSED;
+     asection *input_section;
+     bfd *output_bfd ATTRIBUTE_UNUSED;
+     struct internal_reloc *rel ATTRIBUTE_UNUSED;
+     struct internal_syment *sym ATTRIBUTE_UNUSED;
+     struct reloc_howto_struct *howto;
+     bfd_vma val ATTRIBUTE_UNUSED;
+     bfd_vma addend;
+     bfd_vma *relocation;
+     bfd_byte *contents ATTRIBUTE_UNUSED;
+{
+  howto->pc_relative = true;
+  howto->src_mask &= ~3;
+  howto->dst_mask = howto->src_mask;
+
+  /* A PC relative reloc includes the section address.  */
+  addend += input_section->vma;
+
+  *relocation = val + addend;
+  *relocation -= (input_section->output_section->vma + 
+                 input_section->output_offset);
+  return true;
+}
+
+static boolean 
+xcoff_complain_overflow_dont_func (input_bfd, val, relocation, howto) 
+     bfd *input_bfd ATTRIBUTE_UNUSED;
+     bfd_vma val ATTRIBUTE_UNUSED;
+     bfd_vma relocation ATTRIBUTE_UNUSED;
+     struct reloc_howto_struct *howto ATTRIBUTE_UNUSED;
+{
+  return false;
+}
+
+static boolean 
+xcoff_complain_overflow_bitfield_func (input_bfd, val, relocation, howto) 
+     bfd *input_bfd;
+     bfd_vma val;
+     bfd_vma relocation;
+     struct reloc_howto_struct *howto; 
+{
+  bfd_vma addrmask, fieldmask, signmask, ss;
+  bfd_vma a, b, sum;
+  
+  /* Get the values to be added together.  For signed and unsigned
+     relocations, we assume that all values should be truncated to
+     the size of an address.  For bitfields, all the bits matter.
+     See also bfd_check_overflow.  */
+  fieldmask = N_ONES (howto->bitsize);
+  addrmask = N_ONES (bfd_arch_bits_per_address (input_bfd)) | fieldmask;
+  a = relocation;
+  b = val & howto->src_mask;
+
+  /* Much like unsigned, except no trimming with addrmask.  In
+     addition, the sum overflows if there is a carry out of
+     the bfd_vma, i.e., the sum is less than either input
+     operand.  */
+  a >>= howto->rightshift;
+  b >>= howto->bitpos;
+  
+  /* Bitfields are sometimes used for signed numbers; for
+     example, a 13-bit field sometimes represents values in
+     0..8191 and sometimes represents values in -4096..4095.
+     If the field is signed and a is -4095 (0x1001) and b is
+     -1 (0x1fff), the sum is -4096 (0x1000), but (0x1001 +
+     0x1fff is 0x3000).  It's not clear how to handle this
+     everywhere, since there is not way to know how many bits
+     are significant in the relocation, but the original code
+     assumed that it was fully sign extended, and we will keep
+     that assumption.  */
+  signmask = (fieldmask >> 1) + 1;
+                 
+  if ((a & ~ fieldmask) != 0)
+    {
+      /* Some bits out of the field are set.  This might not
+        be a problem: if this is a signed bitfield, it is OK
+        iff all the high bits are set, including the sign
+        bit.  We'll try setting all but the most significant
+        bit in the original relocation value: if this is all
+        ones, we are OK, assuming a signed bitfield.  */
+      ss = (signmask << howto->rightshift) - 1;
+      if ((ss | relocation) != ~ (bfd_vma) 0)
+       return true;
+      a &= fieldmask;
+    }
+  
+  /* We just assume (b & ~ fieldmask) == 0.  */
+  
+  /* We explicitly permit wrap around if this relocation
+     covers the high bit of an address.  The Linux kernel
+     relies on it, and it is the only way to write assembler
+     code which can run when loaded at a location 0x80000000
+     away from the location at which it is linked.  */
+  if (howto->bitsize + howto->rightshift
+      == bfd_arch_bits_per_address (input_bfd))
+    return false;
+  
+  sum = a + b;
+  if (sum < a || (sum & ~ fieldmask) != 0)
+    {
+      /* There was a carry out, or the field overflow.  Test
+        for signed operands again.  Here is the overflow test
+        is as for complain_overflow_signed.  */
+      if (((~ (a ^ b)) & (a ^ sum)) & signmask)
+       return true;
+    }
+  
+  return false;
+}
+
+static boolean 
+xcoff_complain_overflow_signed_func (input_bfd, val, relocation, howto) 
+     bfd *input_bfd;
+     bfd_vma val;
+     bfd_vma relocation;
+     struct reloc_howto_struct *howto;
+{
+  bfd_vma addrmask, fieldmask, signmask, ss;
+  bfd_vma a, b, sum;
+  
+  /* Get the values to be added together.  For signed and unsigned
+     relocations, we assume that all values should be truncated to
+     the size of an address.  For bitfields, all the bits matter.
+     See also bfd_check_overflow.  */
+  fieldmask = N_ONES (howto->bitsize);
+  addrmask = N_ONES (bfd_arch_bits_per_address (input_bfd)) | fieldmask;
+  a = relocation;
+  b = val & howto->src_mask;
+
+  a = (a & addrmask) >> howto->rightshift;
+  
+  /* If any sign bits are set, all sign bits must be set.
+     That is, A must be a valid negative address after
+     shifting.  */
+  signmask = ~ (fieldmask >> 1);
+  ss = a & signmask;
+  if (ss != 0 && ss != ((addrmask >> howto->rightshift) & signmask))
+    return true;
+  
+  /* We only need this next bit of code if the sign bit of B
+     is below the sign bit of A.  This would only happen if
+     SRC_MASK had fewer bits than BITSIZE.  Note that if
+     SRC_MASK has more bits than BITSIZE, we can get into
+     trouble; we would need to verify that B is in range, as
+     we do for A above.  */
+  signmask = ((~ howto->src_mask) >> 1) & howto->src_mask;
+  if ((b & signmask) != 0)
+    {
+      /* Set all the bits above the sign bit.  */
+      b -= signmask <<= 1;
+    }
+  
+  b = (b & addrmask) >> howto->bitpos;
+  
+  /* Now we can do the addition.  */
+  sum = a + b;
+  
+  /* See if the result has the correct sign.  Bits above the
+     sign bit are junk now; ignore them.  If the sum is
+     positive, make sure we did not have all negative inputs;
+     if the sum is negative, make sure we did not have all
+     positive inputs.  The test below looks only at the sign
+     bits, and it really just
+     SIGN (A) == SIGN (B) && SIGN (A) != SIGN (SUM)
+  */
+  signmask = (fieldmask >> 1) + 1;
+  if (((~ (a ^ b)) & (a ^ sum)) & signmask)
+    return true;
+  
+  return false;
+}
+
+static boolean 
+xcoff_complain_overflow_unsigned_func (input_bfd, val, relocation, howto) 
+     bfd *input_bfd;
+     bfd_vma val;
+     bfd_vma relocation;
+     struct reloc_howto_struct *howto; 
+{
+  bfd_vma addrmask, fieldmask;
+  bfd_vma a, b, sum;
+  
+  /* Get the values to be added together.  For signed and unsigned
+     relocations, we assume that all values should be truncated to
+     the size of an address.  For bitfields, all the bits matter.
+     See also bfd_check_overflow.  */
+  fieldmask = N_ONES (howto->bitsize);
+  addrmask = N_ONES (bfd_arch_bits_per_address (input_bfd)) | fieldmask;
+  a = relocation;
+  b = val & howto->src_mask;
+
+  /* Checking for an unsigned overflow is relatively easy:
+     trim the addresses and add, and trim the result as well.
+     Overflow is normally indicated when the result does not
+     fit in the field.  However, we also need to consider the
+     case when, e.g., fieldmask is 0x7fffffff or smaller, an
+     input is 0x80000000, and bfd_vma is only 32 bits; then we
+     will get sum == 0, but there is an overflow, since the
+     inputs did not fit in the field.  Instead of doing a
+     separate test, we can check for this by or-ing in the
+     operands when testing for the sum overflowing its final
+     field.  */
+  a = (a & addrmask) >> howto->rightshift;
+  b = (b & addrmask) >> howto->bitpos;
+  sum = (a + b) & addrmask;
+  if ((a | b | sum) & ~ fieldmask)
+    return true;
+  
+  return false;
+}
 
 /* This is the relocation function for the RS/6000/POWER/PowerPC.
    This is currently the only processor which uses XCOFF; I hope that
-   will never change.  */
+   will never change.  
+
+   I took the relocation type definitions from two documents:
+   the PowerPC AIX Version 4 Application Binary Interface, First
+   Edition (April 1992), and the PowerOpen ABI, Big-Endian
+   32-Bit Hardware Implementation (June 30, 1994).  Differences
+   between the documents are noted below. 
+
+   Unsupported r_type's 
+
+   R_RTB:
+   R_RRTBI:
+   R_RRTBA:
+       
+   These relocs are defined by the PowerPC ABI to be
+   relative branches which use half of the difference
+   between the symbol and the program counter.  I can't
+   quite figure out when this is useful.  These relocs are
+   not defined by the PowerOpen ABI. 
+
+   Supported r_type's
+
+   R_POS:
+   Simple positive relocation.
+
+   R_NEG:
+   Simple negative relocation. 
+
+   R_REL:
+   Simple PC relative relocation.
+
+   R_TOC:
+   TOC relative relocation.  The value in the instruction in
+   the input file is the offset from the input file TOC to
+   the desired location.  We want the offset from the final
+   TOC to the desired location.  We have:
+   isym = iTOC + in
+   iinsn = in + o
+   osym = oTOC + on
+   oinsn = on + o
+   so we must change insn by on - in.
+
+   R_GL:
+   GL linkage relocation.  The value of this relocation
+   is the address of the entry in the TOC section. 
+
+   R_TCL:
+   Local object TOC address.  I can't figure out the
+   difference between this and case R_GL. 
+
+   R_TRL:
+   TOC relative relocation.  A TOC relative load instruction
+   which may be changed to a load address instruction.
+   FIXME: We don't currently implement this optimization. 
+
+   R_TRLA:
+   TOC relative relocation.  This is a TOC relative load
+   address instruction which may be changed to a load
+   instruction.  FIXME: I don't know if this is the correct
+   implementation.
+
+   R_BA:
+   Absolute branch.  We don't want to mess with the lower
+   two bits of the instruction. 
+
+   R_CAI:
+   The PowerPC ABI defines this as an absolute call which
+   may be modified to become a relative call.  The PowerOpen
+   ABI does not define this relocation type. 
+   
+   R_RBA:
+   Absolute branch which may be modified to become a
+   relative branch. 
+
+   R_RBAC:
+   The PowerPC ABI defines this as an absolute branch to a
+   fixed address which may be modified to an absolute branch
+   to a symbol.  The PowerOpen ABI does not define this
+   relocation type. 
+
+   R_RBRC:
+   The PowerPC ABI defines this as an absolute branch to a
+   fixed address which may be modified to a relative branch.
+   The PowerOpen ABI does not define this relocation type. 
+
+   R_BR:
+   Relative branch.  We don't want to mess with the lower
+   two bits of the instruction. 
+
+   R_CREL:
+   The PowerPC ABI defines this as a relative call which may
+   be modified to become an absolute call.  The PowerOpen
+   ABI does not define this relocation type. 
+
+   R_RBR:
+   A relative branch which may be modified to become an
+   absolute branch.  FIXME: We don't implement this,
+   although we should for symbols of storage mapping class
+   XMC_XO. 
+
+   R_RL:
+   The PowerPC AIX ABI describes this as a load which may be
+   changed to a load address.  The PowerOpen ABI says this
+   is the same as case R_POS. 
+
+   R_RLA:
+   The PowerPC AIX ABI describes this as a load address
+   which may be changed to a load.  The PowerOpen ABI says
+   this is the same as R_POS. 
+*/
 
-static boolean
+boolean
 xcoff_ppc_relocate_section (output_bfd, info, input_bfd,
                            input_section, contents, relocs, syms,
                            sections)
@@ -2429,7 +3319,6 @@ xcoff_ppc_relocate_section (output_bfd, info, input_bfd,
 
   rel = relocs;
   relend = rel + input_section->reloc_count;
-
   for (; rel < relend; rel++)
     {
       long symndx;
@@ -2438,7 +3327,10 @@ xcoff_ppc_relocate_section (output_bfd, info, input_bfd,
       bfd_vma addend;
       bfd_vma val;
       struct reloc_howto_struct howto;
-      bfd_reloc_status_type rstat;
+      bfd_vma relocation;
+      bfd_vma value_to_relocate;
+      bfd_vma address;
+      bfd_byte *location;
 
       /* Relocation type R_REF is a special relocation type which is
          merely used to prevent garbage collection from occurring for
@@ -2446,327 +3338,151 @@ xcoff_ppc_relocate_section (output_bfd, info, input_bfd,
       if (rel->r_type == R_REF)
        continue;
 
-      symndx = rel->r_symndx;
-
-      if (symndx == -1)
-       {
-         h = NULL;
-         sym = NULL;
-         addend = 0;
-       }
-      else
-       {
-         h = obj_xcoff_sym_hashes (input_bfd)[symndx];
-         sym = syms + symndx;
-         addend = - sym->n_value;
-
-       }
-
-      /* We build the howto information on the fly.  */
-
+      /* howto */
       howto.type = rel->r_type;
       howto.rightshift = 0;
-      howto.size = 2;
       howto.bitsize = (rel->r_size & 0x1f) + 1;
+      howto.size = howto.bitsize > 16 ? 2 : 1;
       howto.pc_relative = false;
       howto.bitpos = 0;
-      if ((rel->r_size & 0x80) != 0)
-       howto.complain_on_overflow = complain_overflow_signed;
-      else
-       howto.complain_on_overflow = complain_overflow_bitfield;
+      howto.complain_on_overflow = rel->r_size & 0x80 ? 
+       complain_overflow_signed : complain_overflow_bitfield;
       howto.special_function = NULL;
       howto.name = "internal";
       howto.partial_inplace = true;
-      if (howto.bitsize == 32)
-       howto.src_mask = howto.dst_mask = 0xffffffff;
-      else
-       {
-         howto.src_mask = howto.dst_mask = (1 << howto.bitsize) - 1;
-         if (howto.bitsize == 16)
-           howto.size = 1;
-       }
+      howto.src_mask = howto.dst_mask = N_ONES(howto.bitsize);
       howto.pcrel_offset = false;
 
+      /* symbol */
       val = 0;
+      addend = 0;
+      h = NULL;
+      sym = NULL;
+      symndx = rel->r_symndx;      
 
-      if (h == NULL)
+      if (-1 != symndx)        
        {
          asection *sec;
-
-         if (symndx == -1)
-           {
-             sec = bfd_abs_section_ptr;
-             val = 0;
-           }
-         else
+         
+         h = obj_xcoff_sym_hashes (input_bfd)[symndx];
+         sym = syms + symndx;
+         addend = - sym->n_value;
+         
+         if (NULL == h) 
            {
              sec = sections[symndx];
              /* Hack to make sure we use the right TOC anchor value
-                 if this reloc is against the TOC anchor.  */
-
+                if this reloc is against the TOC anchor.  */
              if (sec->name[3] == '0'
-                         && strcmp (sec->name, ".tc0") == 0)
-               {
-                 val = xcoff_data (output_bfd)->toc;
-               }
+                 && strcmp (sec->name, ".tc0") == 0)
+               val = xcoff_data (output_bfd)->toc;
              else
+               val = (sec->output_section->vma
+                      + sec->output_offset
+                      + sym->n_value
+                      - sec->vma);
+           } 
+         else 
+           {
+             if (h->root.type == bfd_link_hash_defined 
+                 || h->root.type == bfd_link_hash_defweak) 
+               {
+                 sec = h->root.u.def.section;
+                 val = (h->root.u.def.value
+                        + sec->output_section->vma
+                        + sec->output_offset);
+               } 
+             else if (h->root.type == bfd_link_hash_common) 
                {
+                 sec = h->root.u.c.p->section;
                  val = (sec->output_section->vma
-                        + sec->output_offset
-                        + sym->n_value
-                        - sec->vma);
-               }
-           }
-       }
-      else
-       {
-         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 (h->root.type == bfd_link_hash_common)
-           {
-             asection *sec;
-
-             sec = h->root.u.c.p->section;
-             val = (sec->output_section->vma
-                    + sec->output_offset);
-           }
-         else if ((h->flags & XCOFF_DEF_DYNAMIC) != 0
-                  || (h->flags & XCOFF_IMPORT) != 0)
-           {
-             /* Every symbol in a shared object is defined somewhere.  */
-             val = 0;
-           }
-         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;
-
-             /* Don't try to process the reloc.  It can't help, and
-                 it may generate another error.  */
-             continue;
-           }
-       }
-
-      /* I took the relocation type definitions from two documents:
-        the PowerPC AIX Version 4 Application Binary Interface, First
-        Edition (April 1992), and the PowerOpen ABI, Big-Endian
-        32-Bit Hardware Implementation (June 30, 1994).  Differences
-        between the documents are noted below.  */
-
-      switch (rel->r_type)
-       {
-       case R_RTB:
-       case R_RRTBI:
-       case R_RRTBA:
-         /* These relocs are defined by the PowerPC ABI to be
-             relative branches which use half of the difference
-             between the symbol and the program counter.  I can't
-             quite figure out when this is useful.  These relocs are
-             not defined by the PowerOpen ABI.  */
-       default:
-         (*_bfd_error_handler)
-           (_("%s: unsupported relocation type 0x%02x"),
-            bfd_archive_filename (input_bfd), (unsigned int) rel->r_type);
-         bfd_set_error (bfd_error_bad_value);
-         return false;
-       case R_POS:
-         /* Simple positive relocation.  */
-         break;
-       case R_NEG:
-         /* Simple negative relocation.  */
-         val = - val;
-         break;
-       case R_REL:
-         /* Simple PC relative relocation.  */
-         howto.pc_relative = true;
-         break;
-       case R_TOC:
-         /* TOC relative relocation.  The value in the instruction in
-             the input file is the offset from the input file TOC to
-             the desired location.  We want the offset from the final
-             TOC to the desired location.  We have:
-                isym = iTOC + in
-                iinsn = in + o
-                osym = oTOC + on
-                oinsn = on + o
-            so we must change insn by on - in.
-            */
-       case R_GL:
-         /* Global linkage relocation.  The value of this relocation
-             is the address of the entry in the TOC section.  */
-       case R_TCL:
-         /* Local object TOC address.  I can't figure out the
-             difference between this and case R_GL.  */
-       case R_TRL:
-         /* TOC relative relocation.  A TOC relative load instruction
-             which may be changed to a load address instruction.
-             FIXME: We don't currently implement this optimization.  */
-       case R_TRLA:
-         /* TOC relative relocation.  This is a TOC relative load
-             address instruction which may be changed to a load
-             instruction.  FIXME: I don't know if this is the correct
-             implementation.  */
-         if (h != NULL && h->smclas != XMC_TD)
-           {
-             if (h->toc_section == NULL)
+                        + sec->output_offset);
+                 
+               } 
+             else if ((0 == (h->flags & (XCOFF_DEF_DYNAMIC | XCOFF_IMPORT))) 
+                      && ! info->relocateable) 
                {
-                 (*_bfd_error_handler)
-                   (_("%s: TOC reloc at 0x%x to symbol `%s' with no TOC entry"),
-                    bfd_archive_filename (input_bfd), rel->r_vaddr,
-                    h->root.root.string);
-                 bfd_set_error (bfd_error_bad_value);
-                 return false;
+                 if (! ((*info->callbacks->undefined_symbol)
+                        (info, h->root.root.string, input_bfd, input_section,
+                         rel->r_vaddr - input_section->vma, true)))
+                   return false;
+                 
+                 /* Don't try to process the reloc.  It can't help, and
+                    it may generate another error.  */
+                 continue;
                }
-
-             BFD_ASSERT ((h->flags & XCOFF_SET_TOC) == 0);
-             val = (h->toc_section->output_section->vma
-                    + h->toc_section->output_offset);
            }
-
-         val = ((val - xcoff_data (output_bfd)->toc)
-                - (sym->n_value - xcoff_data (input_bfd)->toc));
-         addend = 0;
-         break;
-       case R_BA:
-         /* Absolute branch.  We don't want to mess with the lower
-             two bits of the instruction.  */
-       case R_CAI:
-         /* The PowerPC ABI defines this as an absolute call which
-             may be modified to become a relative call.  The PowerOpen
-             ABI does not define this relocation type.  */
-       case R_RBA:
-         /* Absolute branch which may be modified to become a
-             relative branch.  */
-       case R_RBAC:
-         /* The PowerPC ABI defines this as an absolute branch to a
-             fixed address which may be modified to an absolute branch
-             to a symbol.  The PowerOpen ABI does not define this
-             relocation type.  */
-       case R_RBRC:
-         /* The PowerPC ABI defines this as an absolute branch to a
-             fixed address which may be modified to a relative branch.
-             The PowerOpen ABI does not define this relocation type.  */
-         howto.src_mask &= ~3;
-         howto.dst_mask = howto.src_mask;
-         break;
-       case R_BR:
-         /* Relative branch.  We don't want to mess with the lower
-             two bits of the instruction.  */
-       case R_CREL:
-         /* The PowerPC ABI defines this as a relative call which may
-             be modified to become an absolute call.  The PowerOpen
-             ABI does not define this relocation type.  */
-       case R_RBR:
-         /* A relative branch which may be modified to become an
-             absolute branch.  FIXME: We don't implement this,
-             although we should for symbols of storage mapping class
-             XMC_XO.  */
-         howto.pc_relative = true;
-         howto.src_mask &= ~3;
-         howto.dst_mask = howto.src_mask;
-         break;
-       case R_RL:
-         /* The PowerPC AIX ABI describes this as a load which may be
-             changed to a load address.  The PowerOpen ABI says this
-             is the same as case R_POS.  */
-         break;
-       case R_RLA:
-         /* The PowerPC AIX ABI describes this as a load address
-             which may be changed to a load.  The PowerOpen ABI says
-             this is the same as R_POS.  */
-         break;
        }
 
-      /* If we see an R_BR or R_RBR reloc which is jumping to global
-         linkage code, and it is followed by an appropriate cror nop
-         instruction, we replace the cror with lwz r2,20(r1).  This
-         restores the TOC after the glink code.  Contrariwise, if the
-         call is followed by a lwz r2,20(r1), but the call is not
-         going to global linkage code, we can replace the load with a
-         cror.  */
-      if ((rel->r_type == R_BR || rel->r_type == R_RBR)
-         && h != NULL
-         && h->root.type == bfd_link_hash_defined
-         && (rel->r_vaddr - input_section->vma + 8
-             <= input_section->_cooked_size))
+      if (rel->r_type >= XCOFF_MAX_CALCULATE_RELOCATION 
+         || (false == xcoff_calculate_relocation[rel->r_type]
+             (input_bfd, input_section, output_bfd, rel, sym, &howto, val, 
+              addend, &relocation, contents))) 
+       return false;
+      
+      /* address */
+      address = rel->r_vaddr - input_section->vma;
+      location = contents + address;
+      
+      if (address > input_section->_raw_size)
+       abort();
+
+      /* Get the value we are going to relocate.  */
+      if (1 == howto.size)
+       value_to_relocate = bfd_get_16 (input_bfd, location);
+      else 
+       value_to_relocate = bfd_get_32 (input_bfd, location);
+      
+      /* overflow.  
+        
+        FIXME: We may drop bits during the addition
+        which we don't check for.  We must either check at every single
+        operation, which would be tedious, or we must do the computations
+        in a type larger than bfd_vma, which would be inefficient.  */
+      
+      if ((unsigned int) howto.complain_on_overflow >= 
+         XCOFF_MAX_COMPLAIN_OVERFLOW)
+       abort();
+
+      if ((true == xcoff_complain_overflow[howto.complain_on_overflow]
+          (input_bfd, value_to_relocate, relocation, &howto))) 
        {
-         bfd_byte *pnext;
-         unsigned long next;
-
-         pnext = contents + (rel->r_vaddr - input_section->vma) + 4;
-         next = bfd_get_32 (input_bfd, pnext);
-
-         /* The _ptrgl function is magic.  It is used by the AIX
-             compiler to call a function through a pointer.  */
-         if (h->smclas == XMC_GL
-             || strcmp (h->root.root.string, "._ptrgl") == 0)
+         const char *name;
+         char buf[SYMNMLEN + 1];
+         char reloc_type_name[10];
+         
+         if (symndx == -1) 
            {
-             if (next == 0x4def7b82            /* cror 15,15,15 */
-                 || next == 0x4ffffb82         /* cror 31,31,31 */
-                 || next == 0x60000000)        /* ori r0,r0,0 */
-               bfd_put_32 (input_bfd,
-                           (bfd_vma) 0x80410014, /* lwz r1,20(r1) */
-                           pnext);
-           }
-         else
-           {
-             if (next == 0x80410014)           /* lwz r1,20(r1) */
-               bfd_put_32 (input_bfd,
-                           (bfd_vma) 0x60000000, /* ori r0,r0,0 */
-                           pnext);
-           }
-       }
-
-      /* A PC relative reloc includes the section address.  */
-      if (howto.pc_relative)
-       addend += input_section->vma;
-
-      rstat = _bfd_final_link_relocate (&howto, input_bfd, input_section,
-                                       contents,
-                                       rel->r_vaddr - input_section->vma,
-                                       val, addend);
-
-      switch (rstat)
-       {
-       default:
-         abort ();
-       case bfd_reloc_ok:
-         break;
-       case bfd_reloc_overflow:
-         {
-           const char *name;
-           char buf[SYMNMLEN + 1];
-           char howto_name[10];
-
-           if (symndx == -1)
              name = "*ABS*";
-           else if (h != NULL)
+           } 
+         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;
-             }
-           sprintf (howto_name, "0x%02x", rel->r_type);
-
-           if (! ((*info->callbacks->reloc_overflow)
-                  (info, name, howto_name, (bfd_vma) 0, input_bfd,
-                   input_section, rel->r_vaddr - input_section->vma)))
-             return false;
-         }
+           } 
+         else 
+           {
+             name = _bfd_coff_internal_syment_name (input_bfd, sym, buf);
+             if (name == NULL)
+               name = "UNKNOWN";
+           }
+         sprintf (reloc_type_name, "0x%02x", rel->r_type);
+         
+         if (! ((*info->callbacks->reloc_overflow)
+                (info, name, reloc_type_name, (bfd_vma) 0, input_bfd,
+                 input_section, rel->r_vaddr - input_section->vma)))
+           return false;
        }
+      
+      /* Add RELOCATION to the right bits of VALUE_TO_RELOCATE.  */
+      value_to_relocate = ((value_to_relocate & ~howto.dst_mask) | 
+                          (((value_to_relocate & howto.src_mask) + 
+                            relocation) & howto.dst_mask));
+      
+      /* Put the value back in the object file.  */
+      if (1 == howto.size)
+       bfd_put_16 (input_bfd, value_to_relocate, location);
+      else 
+       bfd_put_32 (input_bfd, value_to_relocate, location);
     }
 
   return true;
@@ -2919,18 +3635,19 @@ xcoff_loader_reloc_offset (abfd, ldhdr)
 }
 
 static boolean 
-xcoff_generate_rtinit  (abfd, init, fini)
+xcoff_generate_rtinit  (abfd, init, fini, rtld)
      bfd *abfd;
      const char *init;
      const char *fini;
+     boolean rtld;
 {
   bfd_byte filehdr_ext[FILHSZ];
   bfd_byte scnhdr_ext[SCNHSZ];
-  bfd_byte syment_ext[SYMESZ * 8];
-  bfd_byte reloc_ext[RELSZ * 2];
+  bfd_byte syment_ext[SYMESZ * 10];
+  bfd_byte reloc_ext[RELSZ * 3];
   bfd_byte *data_buffer;
   bfd_size_type data_buffer_size;
-  bfd_byte *string_table, *st_tmp;
+  bfd_byte *string_table = NULL, *st_tmp = NULL;
   bfd_size_type string_table_size;
   bfd_vma val;
   size_t initsz, finisz;
@@ -2942,9 +3659,9 @@ xcoff_generate_rtinit  (abfd, init, fini)
   
   char *data_name = ".data";
   char *rtinit_name = "__rtinit";
+  char *rtld_name = "__rtld";
   
-  if (! bfd_xcoff_rtinit_size (abfd) 
-      || (init == NULL && fini == NULL))
+  if (! bfd_xcoff_rtinit_size (abfd))
     return false;
 
   initsz = (init == NULL ? 0 : 1 + strlen (init));
@@ -2956,7 +3673,7 @@ xcoff_generate_rtinit  (abfd, init, fini)
   filehdr.f_magic = bfd_xcoff_magic_number (abfd);
   filehdr.f_nscns = 1; 
   filehdr.f_timdat = 0;
-  filehdr.f_nsyms = 0;  /* at least 6, no more than 8 */
+  filehdr.f_nsyms = 0;  /* at least 6, no more than 10 */
   filehdr.f_symptr = 0; /* set below */
   filehdr.f_opthdr = 0;
   filehdr.f_flags = 0;
@@ -2997,8 +3714,10 @@ xcoff_generate_rtinit  (abfd, init, fini)
 
   data_buffer_size = 0x0040 + initsz + finisz;
   data_buffer_size += (data_buffer_size & 7) ? 8 - (data_buffer_size & 7) : 0;
-  data_buffer = (bfd_byte *)bfd_malloc (data_buffer_size);
-  memset (data_buffer, 0, data_buffer_size);
+  data_buffer = NULL;
+  data_buffer = (bfd_byte *) bfd_zmalloc (data_buffer_size);
+  if (data_buffer == NULL)
+    return false;
 
   if (initsz) 
     {
@@ -3032,8 +3751,10 @@ xcoff_generate_rtinit  (abfd, init, fini)
   if (string_table_size)
     {
       string_table_size += 4;
-      string_table = (bfd_byte *)bfd_malloc (string_table_size);
-      memset (string_table, 0, string_table_size);
+      string_table = (bfd_byte *) bfd_zmalloc (string_table_size);
+      if (string_table == NULL)
+       return false;
+
       val = string_table_size;
       bfd_h_put_32 (abfd, val, &string_table[0]);
       st_tmp = string_table + 4;
@@ -3043,9 +3764,10 @@ xcoff_generate_rtinit  (abfd, init, fini)
      0. .data csect
      2. __rtinit
      4. init function 
-     6. fini function */
-  memset (syment_ext, 0, 8 * SYMESZ);
-  memset (reloc_ext, 0, 2 * RELSZ);
+     6. fini function 
+     8. __rtld  */
+  memset (syment_ext, 0, 10 * SYMESZ);
+  memset (reloc_ext, 0, 3 * RELSZ);
 
   /* .data csect */
   memset (&syment, 0, sizeof (struct internal_syment));
@@ -3151,6 +3873,32 @@ xcoff_generate_rtinit  (abfd, init, fini)
       scnhdr.s_nreloc += 1;
     }
 
+  if (rtld)
+    {
+      memset (&syment, 0, sizeof (struct internal_syment));
+      memset (&auxent, 0, sizeof (union internal_auxent));
+      memcpy (syment._n._n_name, rtld_name, strlen (rtld_name));
+      syment.n_sclass = C_EXT;
+      syment.n_numaux = 1;
+      bfd_coff_swap_sym_out (abfd, &syment, 
+                            &syment_ext[filehdr.f_nsyms * SYMESZ]);
+      bfd_coff_swap_aux_out (abfd, &auxent, syment.n_type, syment.n_sclass, 0, 
+                            syment.n_numaux, 
+                            &syment_ext[(filehdr.f_nsyms + 1) * SYMESZ]);
+
+      /* reloc */
+      memset (&reloc, 0, sizeof (struct internal_reloc));
+      reloc.r_vaddr = 0x0000;
+      reloc.r_symndx = filehdr.f_nsyms;
+      reloc.r_type = R_POS;
+      reloc.r_size = 31;
+      bfd_coff_swap_reloc_out (abfd, &reloc, 
+                              &reloc_ext[scnhdr.s_nreloc * RELSZ]);
+
+      filehdr.f_nsyms += 2;
+      scnhdr.s_nreloc += 1;
+    }
+
   scnhdr.s_relptr = scnhdr.s_scnptr + data_buffer_size;
   filehdr.f_symptr = scnhdr.s_relptr + scnhdr.s_nreloc * RELSZ;
 
@@ -3163,6 +3911,9 @@ xcoff_generate_rtinit  (abfd, init, fini)
   bfd_bwrite (syment_ext, filehdr.f_nsyms * SYMESZ, abfd);
   bfd_bwrite (string_table, string_table_size, abfd);
 
+  free (data_buffer);
+  data_buffer = NULL;
+
   return true;
 }
 
@@ -3210,7 +3961,7 @@ static const struct xcoff_backend_data_rec bfd_xcoff_backend_data =
       _bfd_xcoff_swap_aux_out,          /* _bfd_swap_aux_out */
       _bfd_xcoff_swap_sym_out,          /* _bfd_swap_sym_out */
       coff_swap_lineno_out,             /* _bfd_swap_lineno_out */
-      coff_swap_reloc_out,              /* _bfd_swap_reloc_out */
+      xcoff_swap_reloc_out,             /* _bfd_swap_reloc_out */
       coff_swap_filehdr_out,            /* _bfd_swap_filehdr_out */
       coff_swap_aouthdr_out,            /* _bfd_swap_aouthdr_out */
       coff_swap_scnhdr_out,             /* _bfd_swap_scnhdr_out */
@@ -3230,7 +3981,7 @@ static const struct xcoff_backend_data_rec bfd_xcoff_backend_data =
       coff_swap_filehdr_in,             /* _bfd_coff_swap_filehdr_in */
       coff_swap_aouthdr_in,             /* _bfd_swap_aouthdr_in */
       coff_swap_scnhdr_in,              /* _bfd_swap_scnhdr_in */
-      coff_swap_reloc_in,               /* _bfd_reloc_in */
+      xcoff_swap_reloc_in,              /* _bfd_reloc_in */
       coff_bad_format_hook,             /* _bfd_bad_format_hook */
       coff_set_arch_mach_hook,          /* _bfd_set_arch_mach_hook */
       coff_mkobject_hook,               /* _bfd_mkobject_hook */
@@ -3273,14 +4024,11 @@ static const struct xcoff_backend_data_rec bfd_xcoff_backend_data =
     SMALL_AOUTSZ,                       /* _xcoff_small_aout_header_size */
 
   /* Versions. */
-    1,                                    /* _xcoff_ldhdr_version */
+    1,                                   /* _xcoff_ldhdr_version */
 
-    /* Xcoff vs xcoff64 putting symbol names.  */
     _bfd_xcoff_put_symbol_name,          /* _xcoff_put_symbol_name */
-    _bfd_xcoff_put_ldsymbol_name,          /* _xcoff_put_ldsymbol_name */
-
-    & xcoff_dynamic_reloc,                  /* dynamic reloc howto */
-
+    _bfd_xcoff_put_ldsymbol_name,        /* _xcoff_put_ldsymbol_name */
+    & xcoff_dynamic_reloc,               /* dynamic reloc howto */
     xcoff_create_csect_from_smclas,      /* _xcoff_create_csect_from_smclas */
 
     /* Lineno and reloc count overflow.  */
@@ -3299,7 +4047,7 @@ static const struct xcoff_backend_data_rec bfd_xcoff_backend_data =
     xcoff_generate_rtinit,  /* _xcoff_generate_rtinit */
 };
 
-/* The transfer vector that leads the outside world to all of the above. */
+/* The transfer vector that leads the outside world to all of the above.  */
 const bfd_target rs6000coff_vec =
 {
   "aixcoff-rs6000",
@@ -3397,7 +4145,7 @@ const bfd_target rs6000coff_vec =
   _bfd_xcoff_read_ar_hdr,                  /* _read_ar_hdr */
   _bfd_xcoff_openr_next_archived_file,     /* _openr_next_archived_file */
   _bfd_generic_get_elt_at_index,           /* _get_elt_at_index */
-  _bfd_xcoff_generic_stat_arch_elt,        /* _generic_dtat_arch_elt */
+  _bfd_xcoff_stat_arch_elt,                /* _generic_stat_arch_elt */
                                            /* XCOFF archives do not have
                                              a timestamp.  */
   bfd_true,                                /* _update_armap_timestamp */
@@ -3430,11 +4178,14 @@ const bfd_target rs6000coff_vec =
   bfd_generic_get_relocated_section_contents,
   bfd_generic_relax_section,               /* _bfd_relax_section */
   _bfd_xcoff_bfd_link_hash_table_create,   /* _bfd_link_hash_table_create */
+  _bfd_generic_link_hash_table_free,       /* _bfd_link_hash_table_free */
   _bfd_xcoff_bfd_link_add_symbols,         /* _bfd_link_add_symbols */
-  _bfd_xcoff_bfd_final_link,               /* _bfd_filnal_link */
+  _bfd_generic_link_just_syms,             /* _bfd_link_just_syms */
+  _bfd_xcoff_bfd_final_link,               /* _bfd_final_link */
   _bfd_generic_link_split_section,         /* _bfd_link_split_section */
   bfd_generic_gc_sections,                 /* _bfd_gc_sections */
   bfd_generic_merge_sections,              /* _bfd_merge_sections */
+  bfd_generic_discard_group,               /* _bfd_discard_group */
 
   /* Dynamic */
                                           /* _get_dynamic_symtab_upper_bound */
@@ -3469,7 +4220,7 @@ static const struct xcoff_backend_data_rec bfd_pmac_xcoff_backend_data =
     _bfd_xcoff_swap_aux_out,          /* _bfd_swap_aux_out */
     _bfd_xcoff_swap_sym_out,          /* _bfd_swap_sym_out */
     coff_swap_lineno_out,             /* _bfd_swap_lineno_out */
-    coff_swap_reloc_out,              /* _bfd_swap_reloc_out */
+    xcoff_swap_reloc_out,             /* _bfd_swap_reloc_out */
     coff_swap_filehdr_out,            /* _bfd_swap_filehdr_out */
     coff_swap_aouthdr_out,            /* _bfd_swap_aouthdr_out */
     coff_swap_scnhdr_out,             /* _bfd_swap_scnhdr_out */
@@ -3489,7 +4240,7 @@ static const struct xcoff_backend_data_rec bfd_pmac_xcoff_backend_data =
     coff_swap_filehdr_in,             /* _bfd_coff_swap_filehdr_in */
     coff_swap_aouthdr_in,             /* _bfd_swap_aouthdr_in */
     coff_swap_scnhdr_in,              /* _bfd_swap_scnhdr_in */
-    coff_swap_reloc_in,               /* _bfd_reloc_in */
+    xcoff_swap_reloc_in,              /* _bfd_reloc_in */
     coff_bad_format_hook,             /* _bfd_bad_format_hook */
     coff_set_arch_mach_hook,          /* _bfd_set_arch_mach_hook */
     coff_mkobject_hook,               /* _bfd_mkobject_hook */
@@ -3557,7 +4308,6 @@ static const struct xcoff_backend_data_rec bfd_pmac_xcoff_backend_data =
   /* rtinit */
   0,           /* _xcoff_rtinit_size */
   xcoff_generate_rtinit,  /* _xcoff_generate_rtinit */
-
 };
 
 /* The transfer vector that leads the outside world to all of the above. */
@@ -3658,7 +4408,7 @@ const bfd_target pmac_xcoff_vec =
   _bfd_xcoff_read_ar_hdr,                  /* _read_ar_hdr */
   _bfd_xcoff_openr_next_archived_file,     /* _openr_next_archived_file */
   _bfd_generic_get_elt_at_index,           /* _get_elt_at_index */
-  _bfd_xcoff_generic_stat_arch_elt,        /* _generic_dtat_arch_elt */
+  _bfd_xcoff_stat_arch_elt,                /* _generic_stat_arch_elt */
                                            /* XCOFF archives do not have
                                              a timestamp.  */
   bfd_true,                                /* _update_armap_timestamp */
@@ -3691,11 +4441,14 @@ const bfd_target pmac_xcoff_vec =
   bfd_generic_get_relocated_section_contents,
   bfd_generic_relax_section,               /* _bfd_relax_section */
   _bfd_xcoff_bfd_link_hash_table_create,   /* _bfd_link_hash_table_create */
+  _bfd_generic_link_hash_table_free,       /* _bfd_link_hash_table_free */
   _bfd_xcoff_bfd_link_add_symbols,         /* _bfd_link_add_symbols */
-  _bfd_xcoff_bfd_final_link,               /* _bfd_filnal_link */
+  _bfd_generic_link_just_syms,             /* _bfd_link_just_syms */
+  _bfd_xcoff_bfd_final_link,               /* _bfd_final_link */
   _bfd_generic_link_split_section,         /* _bfd_link_split_section */
   bfd_generic_gc_sections,                 /* _bfd_gc_sections */
-  bfd_generic_merge_sections,               /* _bfd_merge_sections */
+  bfd_generic_merge_sections,              /* _bfd_merge_sections */
+  bfd_generic_discard_group,               /* _bfd_discard_group */
 
   /* Dynamic */
                                           /* _get_dynamic_symtab_upper_bound */
This page took 0.054328 seconds and 4 git commands to generate.