* Corrected a one-character typo. All instructions tested in gas/.../vu0.s
[deliverable/binutils-gdb.git] / bfd / coff-ppc.c
index 8f4c986e31c657e317456e8f0d8fe2f17ca028b5..e93be51b58b9063ab22d5e268cc56b43b67fe8e2 100644 (file)
@@ -1,5 +1,5 @@
 /* BFD back-end for PowerPC Microsoft Portable Executable files.
-   Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+   Copyright 1990, 91, 92, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
 
    Original version pieced together by Kim Knuttila (krk@cygnus.com)
 
@@ -26,13 +26,16 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 /* Current State:
    - objdump works
    - relocs generated by gas
+   - ld will link files, but they do not run.
+   - dlltool will not produce correct output in some .reloc cases, and will 
+     not produce the right glue code for dll function calls.
 */
 
 
 #include "bfd.h"
 #include "sysdep.h"
+
 #include "libbfd.h"
-#include "obstack.h"
 
 #include "coff/powerpc.h"
 #include "coff/internal.h"
@@ -47,6 +50,164 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 #include "libcoff.h"
 
+/* The toc is a set of bfd_vma fields. We use the fact that valid         */
+/* addresses are even (i.e. the bit representing "1" is off) to allow     */
+/* us to encode a little extra information in the field                   */
+/* - Unallocated addresses are intialized to 1.                           */
+/* - Allocated addresses are even numbers.                                */
+/* The first time we actually write a reference to the toc in the bfd,    */
+/* we want to record that fact in a fixup file (if it is asked for), so   */
+/* we keep track of whether or not an address has been written by marking */
+/* the low order bit with a "1" upon writing                              */
+
+#define SET_UNALLOCATED(x)  ((x) = 1)
+#define IS_UNALLOCATED(x)   ((x) == 1)
+
+#define IS_WRITTEN(x)       ((x) & 1)
+#define MARK_AS_WRITTEN(x)  ((x) |= 1)
+#define MAKE_ADDR_AGAIN(x)  ((x) &= ~1)
+
+
+/* Turn on this check if you suspect something amiss in the hash tables */
+#ifdef DEBUG_HASH
+
+/* Need a 7 char string for an eye catcher */
+#define EYE "krkjunk"
+
+#define HASH_CHECK_DCL char eye_catcher[8];
+#define HASH_CHECK_INIT(ret)      strcpy(ret->eye_catcher, EYE)
+#define HASH_CHECK(addr) \
+ if (strcmp(addr->eye_catcher, EYE) != 0) \
+  { \
+    fprintf(stderr,\
+    "File %s, line %d, Hash check failure, bad eye %8s\n", \
+    __FILE__, __LINE__, addr->eye_catcher); \
+    abort(); \
+ }
+
+
+#else
+
+#define HASH_CHECK_DCL
+#define HASH_CHECK_INIT(ret)
+#define HASH_CHECK(addr)
+
+#endif
+
+/* In order not to add an int to every hash table item for every coff
+   linker, we define our own hash table, derived from the coff one */
+
+/* PE linker hash table entries. */
+
+struct ppc_coff_link_hash_entry
+{
+  struct coff_link_hash_entry root; /* First entry, as required  */
+
+  /* As we wonder around the relocs, we'll keep the assigned toc_offset
+     here */
+  bfd_vma toc_offset;               /* Our addition, as required */
+  int symbol_is_glue;
+  unsigned long int glue_insn;
+
+  HASH_CHECK_DCL
+};
+
+
+/* PE linker hash table.  */
+
+struct ppc_coff_link_hash_table
+{
+  struct coff_link_hash_table root; /* First entry, as required */
+};
+
+static struct bfd_hash_entry *ppc_coff_link_hash_newfunc
+  PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *,
+          const char *));
+
+/* Routine to create an entry in the link hash table.  */
+
+static struct bfd_hash_entry *
+ppc_coff_link_hash_newfunc (entry, table, string)
+     struct bfd_hash_entry *entry;
+     struct bfd_hash_table *table;
+     const char *string;
+{
+  struct ppc_coff_link_hash_entry *ret = 
+    (struct ppc_coff_link_hash_entry *) entry;
+
+  /* Allocate the structure if it has not already been allocated by a
+     subclass.  */
+  if (ret == (struct ppc_coff_link_hash_entry *) NULL)
+    ret = (struct ppc_coff_link_hash_entry *)
+      bfd_hash_allocate (table, 
+                        sizeof (struct ppc_coff_link_hash_entry));
+
+  if (ret == (struct ppc_coff_link_hash_entry *) NULL)
+    return NULL;
+
+  /* Call the allocation method of the superclass.  */
+  ret = ((struct ppc_coff_link_hash_entry *)
+        _bfd_coff_link_hash_newfunc ((struct bfd_hash_entry *) ret, 
+                                     table, string));
+
+  if (ret)
+    {
+      /* Initialize the local fields.  */
+      SET_UNALLOCATED(ret->toc_offset);
+      ret->symbol_is_glue = 0;
+      ret->glue_insn = 0;
+
+      HASH_CHECK_INIT(ret);
+    }
+
+  return (struct bfd_hash_entry *) ret;
+}
+
+/* Initialize a PE linker hash table.  */
+
+static boolean
+ppc_coff_link_hash_table_init (table, abfd, newfunc)
+     struct ppc_coff_link_hash_table *table;
+     bfd *abfd;
+     struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *,
+                                               struct bfd_hash_table *,
+                                               const char *));
+{
+  return _bfd_coff_link_hash_table_init (&table->root, abfd, newfunc);
+}
+
+/* Create a PE linker hash table.  */
+
+static struct bfd_link_hash_table *
+ppc_coff_link_hash_table_create (abfd)
+     bfd *abfd;
+{
+  struct ppc_coff_link_hash_table *ret;
+
+  ret = ((struct ppc_coff_link_hash_table *)
+        bfd_alloc (abfd, sizeof (struct ppc_coff_link_hash_table)));
+  if (ret == NULL)
+    return NULL;
+  if (! ppc_coff_link_hash_table_init (ret, abfd,
+                                       ppc_coff_link_hash_newfunc))
+    {
+      bfd_release (abfd, ret);
+      return (struct bfd_link_hash_table *) NULL;
+    }
+  return &ret->root.root;
+}
+
+/* Now, tailor coffcode.h to use our hash stuff */
+
+#define coff_bfd_link_hash_table_create ppc_coff_link_hash_table_create
+
+\f
+/* The nt loader points the toc register to &toc + 32768, in order to */
+/* use the complete range of a 16-bit displacement. We have to adjust */
+/* for this when we fix up loads displaced off the toc reg.           */
+#define TOC_LOAD_ADJUSTMENT (-32768)
+#define TOC_SECTION_NAME ".private.toc"
+
 /* The main body of code is in coffcode.h.  */
 
 #define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (3)
@@ -112,6 +273,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #define IMAGE_REL_PPC_REFLO             0x0011
 #define IMAGE_REL_PPC_PAIR              0x0012
 
+/* This is essentially the same as tocrel16, with TOCDEFN assumed */
+#define IMAGE_REL_PPC_TOCREL16_DEFN     0x0013
 
 /*  Flag bits in IMAGE_RELOCATION.TYPE */
 
@@ -147,6 +310,7 @@ static bfd_reloc_status_type ppc_refhi_reloc PARAMS ((bfd *abfd,
                                                      asection *section,
                                                      bfd *output_bfd,
                                                      char **error));
+#if 0
 static bfd_reloc_status_type ppc_reflo_reloc PARAMS ((bfd *abfd,
                                                      arelent *reloc,
                                                      asymbol *symbol,
@@ -154,6 +318,7 @@ static bfd_reloc_status_type ppc_reflo_reloc PARAMS ((bfd *abfd,
                                                      asection *section,
                                                      bfd *output_bfd,
                                                      char **error));
+#endif
 static bfd_reloc_status_type ppc_pair_reloc PARAMS ((bfd *abfd,
                                                     arelent *reloc,
                                                     asymbol *symbol,
@@ -171,6 +336,7 @@ static bfd_reloc_status_type ppc_toc16_reloc PARAMS ((bfd *abfd,
                                                      bfd *output_bfd,
                                                      char **error));
 
+#if 0
 static bfd_reloc_status_type ppc_addr32nb_reloc PARAMS ((bfd *abfd,
                                                         arelent *reloc,
                                                         asymbol *symbol,
@@ -178,7 +344,7 @@ static bfd_reloc_status_type ppc_addr32nb_reloc PARAMS ((bfd *abfd,
                                                         asection *section,
                                                         bfd *output_bfd,
                                                         char **error));
-
+#endif
 static bfd_reloc_status_type ppc_section_reloc PARAMS ((bfd *abfd,
                                                        arelent *reloc,
                                                        asymbol *symbol,
@@ -205,6 +371,7 @@ static bfd_reloc_status_type ppc_imglue_reloc PARAMS ((bfd *abfd,
 
 
 
+static boolean in_reloc_p PARAMS((bfd *abfd, reloc_howto_type *howto));
 
 \f
 /* FIXME: It'll take a while to get through all of these. I only need a few to
@@ -262,22 +429,22 @@ static reloc_howto_type ppc_coff_howto_table[] =
         0x00,                   /* src_mask */                             
         0x00,                   /* dst_mask */                             
         false),                 /* pcrel_offset */
-
+  
   /* IMAGE_REL_PPC_ADDR64 0x0001  64-bit address */
   /* Unused: */
   HOWTO(IMAGE_REL_PPC_ADDR64,    /* type */                                 
-        0,                      /* rightshift */                           
-        3,                      /* size (0 = byte, 1 = short, 2 = long) */ 
-        64,                     /* bitsize */                   
-        false,                  /* pc_relative */                          
-        0,                      /* bitpos */                               
-        complain_overflow_bitfield,     /* complain_on_overflow */
-        0,                      /* special_function */                     
-        "ADDR64",               /* name */
-        true,                   /* partial_inplace */                      
-        MINUS_ONE,              /* src_mask */
-        MINUS_ONE,              /* dst_mask */
-        false),                 /* pcrel_offset */
+       0,                       /* rightshift */                           
+       3,                       /* size (0 = byte, 1 = short, 2 = long) */ 
+       64,                      /* bitsize */                   
+       false,                   /* pc_relative */                          
+       0,                       /* bitpos */                               
+       complain_overflow_bitfield,      /* complain_on_overflow */
+       0,                       /* special_function */                     
+       "ADDR64",               /* name */
+       true,                    /* partial_inplace */                      
+       MINUS_ONE,               /* src_mask */
+       MINUS_ONE,               /* dst_mask */
+       false),                 /* pcrel_offset */
 
   /* IMAGE_REL_PPC_ADDR32 0x0002  32-bit address */
   /* Used: */
@@ -294,10 +461,10 @@ static reloc_howto_type ppc_coff_howto_table[] =
         0xffffffff,            /* src_mask */                             
         0xffffffff,            /* dst_mask */                             
         false),                /* pcrel_offset */
-
+  
   /* IMAGE_REL_PPC_ADDR24 0x0003  26-bit address, shifted left 2 (branch absolute) */
   /* the LI field is in bit 6 through bit 29 is 24 bits, + 2 for the shift */
-  /* Of course, That's the IBM approved bit numbering, which is not what 
+  /* Of course, That's the IBM approved bit numbering, which is not what */
   /* anyone else uses.... The li field is in bit 2 thru 25 */ 
   /* Used: */
   HOWTO (IMAGE_REL_PPC_ADDR24,  /* type */
@@ -313,7 +480,7 @@ static reloc_howto_type ppc_coff_howto_table[] =
         0x07fffffc,            /* src_mask */                             
         0x07fffffc,            /* dst_mask */                             
         false),                /* pcrel_offset */
-
+  
   /* IMAGE_REL_PPC_ADDR16 0x0004  16-bit address */
   /* Used: */
   HOWTO (IMAGE_REL_PPC_ADDR16,  /* type */             
@@ -329,7 +496,7 @@ static reloc_howto_type ppc_coff_howto_table[] =
         0xffff,                /* src_mask */                             
         0xffff,                /* dst_mask */                             
         false),                /* pcrel_offset */
-
+  
   /* IMAGE_REL_PPC_ADDR14 0x0005 */
   /*  16-bit address, shifted left 2 (load doubleword) */
   /* FIXME: the mask is likely wrong, and the bit position may be as well */
@@ -347,7 +514,7 @@ static reloc_howto_type ppc_coff_howto_table[] =
         0xffff,                /* src_mask */                             
         0xffff,                /* dst_mask */                             
         false),                /* pcrel_offset */
-
+  
   /* IMAGE_REL_PPC_REL24 0x0006 */
   /*   26-bit PC-relative offset, shifted left 2 (branch relative) */
   /* Used: */
@@ -364,7 +531,7 @@ static reloc_howto_type ppc_coff_howto_table[] =
         0x3fffffc,             /* src_mask */                             
         0x3fffffc,             /* dst_mask */                             
         false),                /* pcrel_offset */
-
+  
   /* IMAGE_REL_PPC_REL14 0x0007 */
   /*   16-bit PC-relative offset, shifted left 2 (br cond relative) */
   /* FIXME: the mask is likely wrong, and the bit position may be as well */
@@ -383,7 +550,7 @@ static reloc_howto_type ppc_coff_howto_table[] =
         0xffff,                /* src_mask */                             
         0xffff,                /* dst_mask */                             
         true),                 /* pcrel_offset */
-
+  
   /* IMAGE_REL_PPC_TOCREL16 0x0008 */
   /*   16-bit offset from TOC base */
   /* Used: */
@@ -400,7 +567,7 @@ static reloc_howto_type ppc_coff_howto_table[] =
         0xffff,                /* src_mask */                             
         0xffff,                /* dst_mask */                             
         false),                /* pcrel_offset */
-
+  
   /* IMAGE_REL_PPC_TOCREL14 0x0009 */
   /*   16-bit offset from TOC base, shifted left 2 (load doubleword) */
   /* Unused: */
@@ -416,8 +583,8 @@ static reloc_howto_type ppc_coff_howto_table[] =
         false,                 /* partial_inplace */                      
         0xffff,                /* src_mask */                             
         0xffff,                /* dst_mask */                             
-        true),                 /* pcrel_offset */
-
+        false),                /* pcrel_offset */
+  
   /* IMAGE_REL_PPC_ADDR32NB 0x000A */
   /*   32-bit addr w/ image base */
   /* Unused: */
@@ -428,13 +595,13 @@ static reloc_howto_type ppc_coff_howto_table[] =
         false,                 /* pc_relative */                          
         0,                     /* bitpos */                               
         complain_overflow_signed, /* complain_on_overflow */
-        ppc_addr32nb_reloc,    /* special_function */                     
+        0,                     /* special_function */                     
         "ADDR32NB",            /* name */
         true,                  /* partial_inplace */                      
         0xffffffff,            /* src_mask */                             
         0xffffffff,            /* dst_mask */                             
-        true),                 /* pcrel_offset */
-
+        false),                 /* pcrel_offset */
+  
   /* IMAGE_REL_PPC_SECREL 0x000B */
   /*   va of containing section (as in an image sectionhdr) */
   /* Unused: */
@@ -484,7 +651,7 @@ static reloc_howto_type ppc_coff_howto_table[] =
         true,                  /* partial_inplace */                      
         0xffffffff,            /* src_mask */                             
         0xffffffff,            /* dst_mask */                             
-        true),                 /* pcrel_offset */
+        false),                /* pcrel_offset */
 
   /* IMAGE_REL_PPC_IMGLUE 0x000E */
   /*   symbol is glue code; virtual address is TOC restore instruction */
@@ -566,40 +733,273 @@ static reloc_howto_type ppc_coff_howto_table[] =
         true,                  /* partial_inplace */                      
         0xffffffff,            /* src_mask */                             
         0xffffffff,            /* dst_mask */                             
-        false)                 /* pcrel_offset */
+        false),                /* pcrel_offset */
+
+  /* IMAGE_REL_PPC_TOCREL16_DEFN 0x0013 */
+  /*   16-bit offset from TOC base, without causing a definition */
+  /* Used: */
+  HOWTO ( (IMAGE_REL_PPC_TOCREL16 | IMAGE_REL_PPC_TOCDEFN), /* type */ 
+        0,                     /* rightshift */                           
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */ 
+        16,                    /* bitsize */                   
+        false,                 /* pc_relative */                          
+        0,                     /* bitpos */                               
+        complain_overflow_dont, /* complain_on_overflow */
+        0,                     /* special_function */                     
+        "TOCREL16, TOCDEFN",   /* name */
+        false,                 /* partial_inplace */                      
+        0xffff,                /* src_mask */                             
+        0xffff,                /* dst_mask */                             
+        false),                /* pcrel_offset */
+
 };
 
 
-/* Provided the symbol, returns the value reffed */
-static long get_symbol_value PARAMS ((asymbol *));
+\f
 
-static long
-get_symbol_value (symbol)       
-     asymbol *symbol;
-{                                             
-  long relocation = 0;
+/* Some really cheezy macros that can be turned on to test stderr :-) */
 
-  if (bfd_is_com_section (symbol->section))
-  {
-    relocation = 0;                           
-  }
-  else 
-  {                                      
-    relocation = symbol->value +
-     symbol->section->output_section->vma +
-      symbol->section->output_offset;
-  }                                           
-
-  return(relocation);
+#ifdef DEBUG_RELOC
+#define UN_IMPL(x)                                           \
+{                                                            \
+   static int i;                                             \
+   if (i == 0)                                               \
+     {                                                       \
+       i = 1;                                                \
+       fprintf(stderr,"Unimplemented Relocation -- %s\n",x); \
+     }                                                       \
+}
+
+#define DUMP_RELOC(n,r)                              \
+{                                                    \
+   fprintf(stderr,"%s sym %d, addr %d, addend %d\n", \
+          n, (*(r->sym_ptr_ptr))->name,             \
+          r->address, r->addend);                   \
+}
+
+/* Given a reloc name, n, and a pointer to an internal_reloc, 
+   dump out interesting information on the contents 
+
+#define n_name         _n._n_name
+#define n_zeroes       _n._n_n._n_zeroes
+#define n_offset       _n._n_n._n_offset
+
+*/
+
+#define DUMP_RELOC2(n,r)                     \
+{                                            \
+   fprintf(stderr,"%s sym %d, r_vaddr %d %s\n", \
+          n, r->r_symndx, r->r_vaddr,\
+          (((r->r_type) & IMAGE_REL_PPC_TOCDEFN) == 0) \
+          ?" ":" TOCDEFN"  );      \
+}
+
+#else
+#define UN_IMPL(x)
+#define DUMP_RELOC(n,r)
+#define DUMP_RELOC2(n,r)
+#endif
+
+
+\f
+/* toc construction and management routines */
+extern bfd* bfd_of_toc_owner;
+extern long int global_toc_size;
+
+extern long int import_table_size;
+extern long int first_thunk_address;
+extern long int thunk_size;
+
+enum toc_type
+{
+  default_toc,
+  toc_32,
+  toc_64
+};
+
+enum ref_category
+{
+  priv,
+  pub,
+  data
+};
+
+struct list_ele
+{
+  struct list_ele *next;
+  bfd_vma addr;
+  enum ref_category cat;
+  int offset;
+  const char *name;
+};
+
+extern struct list_ele *head;
+extern struct list_ele *tail;
+
+static void
+record_toc(toc_section, our_toc_offset, cat, name)
+     asection *toc_section;
+     int our_toc_offset;
+     enum ref_category cat;
+     const char *name;
+{
+  /* add this entry to our toc addr-offset-name list */
+  struct list_ele *t;
+  t = (struct list_ele *) bfd_malloc (sizeof (struct list_ele));
+  if (t == NULL)
+    abort ();
+  t->next = 0;
+  t->offset = our_toc_offset;
+  t->name = name;
+  t->cat = cat;
+  t->addr = toc_section->output_offset + our_toc_offset;
+
+  if (head == 0)
+    {
+      head = t;
+      tail = t;
+    }
+  else
+    {
+      tail->next = t;
+      tail = t;
+    }
+}
+
+#ifdef COFF_IMAGE_WITH_PE
+
+/* record a toc offset against a symbol */
+static boolean
+ppc_record_toc_entry(abfd, info, sec, sym, toc_kind)
+     bfd *abfd;
+     struct bfd_link_info *info;
+     asection *sec;
+     int sym;
+     enum toc_type toc_kind;
+{
+  struct ppc_coff_link_hash_entry *h;
+  const char *name;
+
+  int *local_syms;
+
+  h = 0;
+
+  h = (struct ppc_coff_link_hash_entry *) (obj_coff_sym_hashes (abfd)[sym]);
+  if (h != 0)
+    {
+      HASH_CHECK(h);
+    }
+
+  if (h == 0) 
+    { 
+      local_syms = obj_coff_local_toc_table(abfd);
+      if (local_syms == 0)
+       {
+         int i;
+         /* allocate a table */
+         local_syms = 
+           (int *) bfd_zalloc (abfd, 
+                               obj_raw_syment_count(abfd) * sizeof(int));
+         if (local_syms == 0)
+           return false;
+         obj_coff_local_toc_table(abfd) = local_syms;
+         for (i = 0; i < obj_raw_syment_count(abfd); ++i)
+           {
+             SET_UNALLOCATED(local_syms[i]);
+           }
+       }
+
+      if (IS_UNALLOCATED(local_syms[sym])) 
+       {
+         local_syms[sym] = global_toc_size;
+         global_toc_size += 4;
+
+         /* The size must fit in a 16bit displacment */
+         if (global_toc_size > 65535)
+           {
+             (*_bfd_error_handler) ("TOC overflow");
+             bfd_set_error (bfd_error_file_too_big);
+             return false;
+           }
+       }
+    }
+  else
+    {
+      name = h->root.root.root.string;
+
+      /* check to see if there's a toc slot allocated. If not, do it
+        here. It will be used in relocate_section */
+      if (IS_UNALLOCATED(h->toc_offset))
+       {
+         h->toc_offset = global_toc_size;
+         global_toc_size += 4;
+
+         /* The size must fit in a 16bit displacment */
+         if (global_toc_size >= 65535)
+           {
+             (*_bfd_error_handler) ("TOC overflow");
+             bfd_set_error (bfd_error_file_too_big);
+             return false;
+           }
+       }
+    }
+
+  return true;
+}
+
+/* record a toc offset against a symbol */
+static void
+ppc_mark_symbol_as_glue(abfd, sym, rel)
+     bfd *abfd;
+     int sym;
+     struct internal_reloc *rel;
+{
+  struct ppc_coff_link_hash_entry *h;
+
+  h = (struct ppc_coff_link_hash_entry *) (obj_coff_sym_hashes (abfd)[sym]);
+
+  HASH_CHECK(h);
+
+  h->symbol_is_glue = 1;
+  h->glue_insn = bfd_get_32 (abfd, (bfd_byte *) &rel->r_vaddr);
+
+  return;
 }
 
+#endif /* COFF_IMAGE_WITH_PE */
+\f
+
+/* Return true if this relocation should
+   appear in the output .reloc section. */
+
+static boolean in_reloc_p(abfd, howto)
+     bfd * abfd;
+     reloc_howto_type *howto;
+{
+  return 
+    (! howto->pc_relative) 
+      && (howto->type != IMAGE_REL_PPC_ADDR32NB)
+      && (howto->type != IMAGE_REL_PPC_TOCREL16)
+      && (howto->type != IMAGE_REL_PPC_IMGLUE)
+      && (howto->type != IMAGE_REL_PPC_IFGLUE) 
+      && (howto->type != IMAGE_REL_PPC_SECREL)
+      && (howto->type != IMAGE_REL_PPC_SECTION)
+      && (howto->type != IMAGE_REL_PPC_SECREL16)
+      && (howto->type != IMAGE_REL_PPC_REFHI)
+      && (howto->type != IMAGE_REL_PPC_REFLO)
+      && (howto->type != IMAGE_REL_PPC_PAIR)
+      && (howto->type != IMAGE_REL_PPC_TOCREL16_DEFN) ;
+}     
+
+#if 0
+
 /* this function is in charge of performing all the ppc PE relocations */
 /* Don't yet know if we want to do this this particular way ... (krk)  */
-/* (it is not yet enabled) */
+/* FIXME: (it is not yet enabled) */
 
 static bfd_reloc_status_type
 pe_ppc_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd,
-           error_message)
+             error_message)
      bfd *abfd;
      arelent *reloc_entry;
      asymbol *symbol_in;
@@ -613,151 +1013,51 @@ pe_ppc_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd,
   static boolean part1_consth_active = false;
   static unsigned long part1_consth_value;
 
-  unsigned long insn;
   unsigned long sym_value;
-  unsigned long unsigned_value;
   unsigned short r_type;
-  long signed_value;
-
   unsigned long addr = reloc_entry->address ; /*+ input_section->vma*/
-  bfd_byte  *hit_data =addr + (bfd_byte *)(data);
        
   r_type = reloc_entry->howto->type;
 
-  if (output_bfd) {
-    /* Partial linking - do nothing */
-    reloc_entry->address += input_section->output_offset;
-    return bfd_reloc_ok;
-
-  }
+  if (output_bfd) 
+    {
+      /* Partial linking - do nothing */
+      reloc_entry->address += input_section->output_offset;
+      return bfd_reloc_ok; 
+    }
 
   if (symbol_in != NULL
       && bfd_is_und_section (symbol_in->section))
-  {
-    /* Keep the state machine happy in case we're called again */
-    if (r_type == IMAGE_REL_PPC_REFHI) 
     {
-      part1_consth_active = true;
-      part1_consth_value  = 0;
+      /* Keep the state machine happy in case we're called again */
+      if (r_type == IMAGE_REL_PPC_REFHI) 
+       {
+         part1_consth_active = true;
+         part1_consth_value  = 0;
+       }
+      return(bfd_reloc_undefined);
     }
-    return(bfd_reloc_undefined);
-  }
-
+  
   if ((part1_consth_active) && (r_type != IMAGE_REL_PPC_PAIR)) 
-  {
-    part1_consth_active = false;
-    *error_message = (char *) "Missing PAIR";
-    return(bfd_reloc_dangerous);
-  }
-
-
-  sym_value = get_symbol_value(symbol_in);
-
-#if 0
-
-  switch (r_type) 
-  {
-   case R_IREL:        
-    insn = bfd_get_32(abfd, hit_data); 
-    /* Take the value in the field and sign extend it */
-    signed_value = EXTRACT_HWORD(insn);
-    signed_value = SIGN_EXTEND_HWORD(signed_value);
-    signed_value <<= 2;
-    signed_value +=  sym_value + reloc_entry->addend;
-    if (((signed_value + reloc_entry->address) & ~0x3ffff) == 0)
-    {                          /* Absolute jmp/call */
-      insn |= (1<<24);         /* Make it absolute */
-      signed_value += reloc_entry->address;
-      /* FIXME: Should we change r_type to R_IABS */
-    } 
-    else 
     {
-      /* Relative jmp/call, so subtract from the value the
-        address of the place we're coming from */
-      signed_value -= (input_section->output_section->vma
-                      + input_section->output_offset);
-      if (signed_value>0x1ffff || signed_value<-0x20000) 
-       return(bfd_reloc_overflow);
-    }
-    signed_value >>= 2;
-    insn = INSERT_HWORD(insn, signed_value);
-    bfd_put_32(abfd, insn ,hit_data); 
-    break;
-   case R_ILOHALF: 
-    insn = bfd_get_32(abfd, hit_data); 
-    unsigned_value = EXTRACT_HWORD(insn);
-    unsigned_value +=  sym_value + reloc_entry->addend;
-    insn = INSERT_HWORD(insn, unsigned_value);
-    bfd_put_32(abfd, insn, hit_data); 
-    break;
-   case R_IHIHALF:
-    insn = bfd_get_32(abfd, hit_data); 
-    /* consth, part 1 
-       Just get the symbol value that is referenced */
-    part1_consth_active = true;
-    part1_consth_value = sym_value + reloc_entry->addend;
-    /* Don't modify insn until R_IHCONST */
-    break;
-   case R_IHCONST:     
-    insn = bfd_get_32(abfd, hit_data); 
-    /* consth, part 2 
-       Now relocate the reference */
-    if (part1_consth_active == false) {
-      *error_message = (char *) "Missing IHIHALF";
+      part1_consth_active = false;
+      *error_message = (char *) "Missing PAIR";
       return(bfd_reloc_dangerous);
     }
-    /* sym_ptr_ptr = r_symndx, in coff_slurp_reloc_table() */
-    unsigned_value = 0;                /*EXTRACT_HWORD(insn) << 16;*/
-    unsigned_value += reloc_entry->addend; /* r_symndx */
-    unsigned_value += part1_consth_value;
-    unsigned_value = unsigned_value >> 16;
-    insn = INSERT_HWORD(insn, unsigned_value);
-    part1_consth_active = false;
-    bfd_put_32(abfd, insn, hit_data); 
-    break;
-   case R_BYTE:
-    insn = bfd_get_8(abfd, hit_data); 
-    unsigned_value = insn + sym_value + reloc_entry->addend;   
-    if (unsigned_value & 0xffffff00) {
-      fprintf(stderr,"Relocation problem : ");
-      fprintf(stderr,"byte value too large in module %s\n",
-             abfd->filename); 
-      return(bfd_reloc_overflow);
-    }
-    bfd_put_8(abfd, unsigned_value, hit_data); 
-    break;
-   case R_HWORD:
-    insn = bfd_get_16(abfd, hit_data); 
-    unsigned_value = insn + sym_value + reloc_entry->addend;   
-    if (unsigned_value & 0xffff0000) {
-      fprintf(stderr,"Relocation problem : ");
-      fprintf(stderr,"hword value too large in module %s\n",
-             abfd->filename); 
-      return(bfd_reloc_overflow);
-    }
 
-    bfd_put_16(abfd, insn, hit_data); 
-    break;
-   case R_WORD:
-    insn = bfd_get_32(abfd, hit_data); 
-    insn += sym_value + reloc_entry->addend;  
-    bfd_put_32(abfd, insn, hit_data);
-    break;
-   default:
-    *error_message = "Unrecognized reloc";
-    return (bfd_reloc_dangerous);
-  }
-
-#endif
 
+  sym_value = get_symbol_value(symbol_in);
+  
   return(bfd_reloc_ok);        
 }
 
+#endif /* 0 */
+
 /* The reloc processing routine for the optimized COFF linker.  */
 
 static boolean
 coff_ppc_relocate_section (output_bfd, info, input_bfd, input_section,
-                           contents, relocs, syms, sections)
+                          contents, relocs, syms, sections)
      bfd *output_bfd;
      struct bfd_link_info *info;
      bfd *input_bfd;
@@ -771,19 +1071,16 @@ coff_ppc_relocate_section (output_bfd, info, input_bfd, input_section,
   struct internal_reloc *relend;
   boolean hihalf;
   bfd_vma hihalf_val;
-
-  unsigned short r_type  = EXTRACT_TYPE (rel->r_type);
-  unsigned short r_flags = EXTRACT_FLAGS(rel->r_type);
-  unsigned short junk    = EXTRACT_JUNK (rel->r_type);
-
-
+  asection *toc_section = 0;
+  bfd_vma relocation;
+  reloc_howto_type *howto = 0;
+  
   /* If we are performing a relocateable link, we don't need to do a
      thing.  The caller will take care of adjusting the reloc
      addresses and symbol indices.  */
-
   if (info->relocateable)
     return true;
-
+  
   hihalf = false;
   hihalf_val = 0;
 
@@ -792,124 +1089,674 @@ coff_ppc_relocate_section (output_bfd, info, input_bfd, input_section,
   for (; rel < relend; rel++)
     {
       long symndx;
-      bfd_byte *loc;
-      struct coff_link_hash_entry *h;
+      struct ppc_coff_link_hash_entry *h;
       struct internal_syment *sym;
-      asection *sec;
       bfd_vma val;
-      boolean overflow;
-      unsigned long insn;
-      long signed_value;
-      unsigned long unsigned_value;
+
+      asection *sec;
       bfd_reloc_status_type rstat;
+      bfd_byte *loc;
 
+      unsigned short r_type  = EXTRACT_TYPE (rel->r_type);
+      unsigned short r_flags = EXTRACT_FLAGS(rel->r_type);
+  
       symndx = rel->r_symndx;
       loc = contents + rel->r_vaddr - input_section->vma;
 
+      /* FIXME: check bounds on r_type */
+      howto = ppc_coff_howto_table + r_type;
+
       if (symndx == -1)
-       h = NULL;
+       {
+         h = NULL;
+         sym = NULL;
+       }
       else
-       h = obj_coff_sym_hashes (input_bfd)[symndx];
-
-      sym = NULL;
-      sec = NULL;
-      val = 0;
+       {
+         h = (struct ppc_coff_link_hash_entry *) 
+           (obj_coff_sym_hashes (input_bfd)[symndx]);
+         if (h != 0) 
+           {
+             HASH_CHECK(h);
+           }
 
-      overflow = false;
+         sym = syms + symndx;
+       }
 
+      if (r_type == IMAGE_REL_PPC_IMGLUE && h == 0)
+       {
+         /* An IMGLUE reloc must have a name. Something is very wrong. */
+         abort();
+       }
+
+      sec = NULL;
+      val = 0;
+
+      /* FIXME: PAIR unsupported in the following code */
+      if (h == NULL)
+       {
+         if (symndx == -1)
+           sec = bfd_abs_section_ptr;
+         else
+           {
+             sec = sections[symndx];
+             val = (sec->output_section->vma
+                    + sec->output_offset
+                    + sym->n_value
+                    - sec->vma);
+           }
+       }
+      else
+       {
+         HASH_CHECK(h);
+
+         if (h->root.root.type == bfd_link_hash_defined
+             || h->root.root.type == bfd_link_hash_defweak)
+           {
+             sec = h->root.root.u.def.section;
+             val = (h->root.root.u.def.value
+                    + sec->output_section->vma
+                    + sec->output_offset);
+           }
+         else
+           {
+             if (! ((*info->callbacks->undefined_symbol)
+                    (info, h->root.root.root.string, input_bfd, input_section,
+                     rel->r_vaddr - input_section->vma)))
+               return false;
+           }
+       }
+
+      rstat = bfd_reloc_ok;
+      
+      /* Each case must do its own relocation, setting rstat appropriately */
       switch (r_type)
        {
        default:
-         fprintf( stderr, "unsupported reloc %s\n",
-                 ppc_coff_howto_table[r_type].name);
+         (*_bfd_error_handler)
+           ("%s: unsupported relocation type 0x%02x",
+            bfd_get_filename (input_bfd), r_type);
          bfd_set_error (bfd_error_bad_value);
          return false;
        case IMAGE_REL_PPC_TOCREL16:
+         {
+           bfd_vma our_toc_offset;
+           int fixit;
+
+           DUMP_RELOC2(howto->name, rel);
+
+           if (toc_section == 0) 
+             {
+               toc_section = bfd_get_section_by_name (bfd_of_toc_owner, 
+                                                      TOC_SECTION_NAME);
+
+               if ( toc_section == NULL ) 
+                 {
+                   /* There is no toc section. Something is very wrong. */
+                   abort();
+                 }
+             }
+
+           /* 
+            *  Amazing bit tricks present. As we may have seen earlier, we
+            *  use the 1 bit to tell us whether or not a toc offset has been
+            *  allocated. Now that they've all been allocated, we will use
+            *  the 1 bit to tell us if we've written this particular toc
+            *  entry out.
+            */
+           fixit = false;
+           if (h == 0)
+             { /* it is a file local symbol */
+               int *local_toc_table;
+               const char *name;
+
+               sym = syms + symndx;
+               name = sym->_n._n_name;
+
+               local_toc_table = obj_coff_local_toc_table(input_bfd);
+               our_toc_offset = local_toc_table[symndx];
+
+               if (IS_WRITTEN(our_toc_offset))
+                 {
+                   /* if it has been written out, it is marked with the 
+                      1 bit. Fix up our offset, but do not write it out
+                      again.
+                    */
+                   MAKE_ADDR_AGAIN(our_toc_offset);
+                 }
+               else
+                 {
+                   /* write out the toc entry */
+                   record_toc(toc_section, 
+                              our_toc_offset, 
+                              priv, 
+                              strdup(name));
+
+                   bfd_put_32(output_bfd,
+                              val,
+                              toc_section->contents + our_toc_offset);
+
+                   MARK_AS_WRITTEN(local_toc_table[symndx]);
+                   fixit = true;
+                 }
+             }
+           else
+             {
+               const char *name = h->root.root.root.string;
+               our_toc_offset = h->toc_offset;
+
+               if ((r_flags & IMAGE_REL_PPC_TOCDEFN) 
+                   == IMAGE_REL_PPC_TOCDEFN )
+                 {
+                   /* This is unbelievable cheese. Some knowledgable asm 
+                      hacker has decided to use r2 as a base for loading 
+                      a value. He/She does this by setting the tocdefn bit, 
+                      and not supplying a toc definition. The behaviour is 
+                      then to use the difference between the value of the 
+                      symbol and the actual location of the toc as the toc 
+                      index. 
+
+                      In fact, what is usually happening is, because the
+                      Import Address Table is mapped immediately following
+                      the toc, some trippy library code trying for speed on
+                      dll linkage, takes advantage of that and considers 
+                      the IAT to be part of the toc, thus saving a load.
+                   */
+
+                   our_toc_offset = val - 
+                     (toc_section->output_section->vma + 
+                      toc_section->output_offset);
+
+                   /* The size must still fit in a 16bit displacment */
+                   if (our_toc_offset >= 65535)
+                     {
+                       (*_bfd_error_handler)
+                         ("%s: Relocation for %s of %x exceeds Toc size limit", 
+                          bfd_get_filename (input_bfd), name, our_toc_offset);
+                       bfd_set_error (bfd_error_bad_value);
+                       return false;
+                     }
+
+                   record_toc(toc_section, our_toc_offset, pub, strdup(name));
+                 }
+               else if (IS_WRITTEN(our_toc_offset))
+                 {
+                   /* if it has been written out, it is marked with the 
+                      1 bit. Fix up our offset, but do not write it out
+                      again.
+                    */
+                   MAKE_ADDR_AGAIN(our_toc_offset);
+                 }
+               else
+                 {
+                   record_toc(toc_section, our_toc_offset, pub, strdup(name));
+
+                   /* write out the toc entry */
+                   bfd_put_32(output_bfd,
+                              val,
+                              toc_section->contents + our_toc_offset);
+
+                   MARK_AS_WRITTEN(h->toc_offset);
+                   /* The tricky part is that this is the address that */
+                   /* needs a .reloc entry for it */
+                   fixit = true;
+                 }
+             }
+
+           if (fixit && info->base_file) 
+             {
+               /* So if this is non pcrelative, and is referenced
+                  to a section or a common symbol, then it needs a reloc */
+
+               /* relocation to a symbol in a section which
+                  isn't absolute - we output the address here 
+                  to a file */
+
+               bfd_vma addr =  toc_section->output_section->vma
+                 + toc_section->output_offset + our_toc_offset;
+                   
+               if (coff_data(output_bfd)->pe)
+                 addr -= pe_data(output_bfd)->pe_opthdr.ImageBase;
+
+               fwrite (&addr, 1,4, (FILE *) info->base_file);
+             }
+
+
+           /* FIXME: this test is conservative */
+           if ( (r_flags & IMAGE_REL_PPC_TOCDEFN) != IMAGE_REL_PPC_TOCDEFN &&
+               our_toc_offset > toc_section->_raw_size)
+             {
+               (*_bfd_error_handler)
+                 ("%s: Relocation exceeds allocated TOC (%x)", 
+                  bfd_get_filename (input_bfd),
+                  toc_section->_raw_size);
+               bfd_set_error (bfd_error_bad_value);
+               return false;
+             }
+
+           /* Now we know the relocation for this toc reference */
+           relocation =  our_toc_offset + TOC_LOAD_ADJUSTMENT;
+           rstat = _bfd_relocate_contents (howto,
+                                           input_bfd, 
+                                           relocation, 
+                                           loc);
+         }
+         break;
        case IMAGE_REL_PPC_IFGLUE:
-       case IMAGE_REL_PPC_SECTION:
+         {
+           /* To solve this, we need to know whether or not the symbol */
+           /* appearing on the call instruction is a glue function or not. */
+           /* A glue function must announce itself via a IMGLUE reloc, and */
+           /* the reloc contains the required toc restore instruction */
+         
+           bfd_vma x;
+           const char *my_name;
+           DUMP_RELOC2(howto->name, rel);
+
+           if (h != 0)
+             {
+               my_name = h->root.root.root.string;
+               if (h->symbol_is_glue == 1) 
+                 {
+                   x = bfd_get_32(input_bfd, loc);
+                   bfd_put_32(input_bfd, h->glue_insn, loc);
+                 }
+             }
+         }
+         break;
        case IMAGE_REL_PPC_SECREL:
-       case IMAGE_REL_PPC_IMGLUE:
+         /* Unimplemented: codeview debugging information */
+         /* For fast access to the header of the section 
+            containing the item. */
+         break;
+       case IMAGE_REL_PPC_SECTION:
+         /* Unimplemented: codeview debugging information */
+         /* Is used to indicate that the value should be relative
+            to the beginning of the section that contains the
+            symbol */
+         break;
        case IMAGE_REL_PPC_ABSOLUTE:
+         {
+           const char *my_name;
+           if (h == 0)
+               my_name = (syms+symndx)->_n._n_name;
+           else
+             {
+               my_name = h->root.root.root.string;
+             }
+
+           fprintf(stderr, 
+                   "Warning: unsupported reloc %s <file %s, section %s>\n", 
+                   howto->name,
+                   bfd_get_filename(input_bfd),
+                   input_section->name);
+
+           fprintf(stderr,"sym %ld (%s), r_vaddr %ld (%lx)\n", 
+                   rel->r_symndx, my_name, (long) rel->r_vaddr,
+                   (unsigned long) rel->r_vaddr);  
+         }
+         break;
+       case IMAGE_REL_PPC_IMGLUE:
+         {
+           /* There is nothing to do now. This reloc was noted in the first
+              pass over the relocs, and the glue instruction extracted */
+           const char *my_name;
+           if (h->symbol_is_glue == 1) 
+             break;
+           my_name = h->root.root.root.string;
+
+           (*_bfd_error_handler)
+             ("%s: Out of order IMGLUE reloc for %s", 
+              bfd_get_filename (input_bfd), my_name);
+           bfd_set_error (bfd_error_bad_value);
+           return false;
+         }
+
+       case IMAGE_REL_PPC_ADDR32NB:
+         {
+           struct coff_link_hash_entry *myh = 0;
+           const char *name = 0;
+           DUMP_RELOC2(howto->name, rel);
+
+           if (strncmp(".idata$2",input_section->name,8) == 0 && first_thunk_address == 0)
+             {
+               /* set magic values */
+               int idata5offset;
+               struct coff_link_hash_entry *myh = 0;
+               myh = coff_link_hash_lookup (coff_hash_table (info),
+                                            "__idata5_magic__",
+                                            false, false, true);
+               first_thunk_address = myh->root.u.def.value + 
+                 sec->output_section->vma + 
+                   sec->output_offset - 
+                     pe_data(output_bfd)->pe_opthdr.ImageBase;
+               
+               idata5offset = myh->root.u.def.value;
+               myh = coff_link_hash_lookup (coff_hash_table (info),
+                                            "__idata6_magic__",
+                                            false, false, true);
+               
+               thunk_size = myh->root.u.def.value - idata5offset;
+               myh = coff_link_hash_lookup (coff_hash_table (info),
+                                            "__idata4_magic__",
+                                            false, false, true);
+               import_table_size = myh->root.u.def.value;
+             }
+
+           if (h == 0)
+             { /* it is a file local symbol */
+               sym = syms + symndx;
+               name = sym->_n._n_name;
+             }
+           else
+             {
+               char *target = 0;
+
+               name = h->root.root.root.string;
+               if (strcmp(".idata$2", name) == 0)
+                 target = "__idata2_magic__";
+               else if (strcmp(".idata$4", name) == 0)
+                 target = "__idata4_magic__";
+               else if (strcmp(".idata$5", name) == 0)
+                 target = "__idata5_magic__";
+
+               if (target != 0)
+                 {
+                   myh = 0;
+
+                   myh = coff_link_hash_lookup (coff_hash_table (info),
+                                                target,
+                                                false, false, true);
+                   if (myh == 0) 
+                     {
+                       /* Missing magic cookies. Something is very wrong. */
+                       abort();
+                     }
+                   
+                   val = myh->root.u.def.value + 
+                     sec->output_section->vma + sec->output_offset;
+                   if (first_thunk_address == 0)
+                     {
+                       int idata5offset;
+                       myh = coff_link_hash_lookup (coff_hash_table (info),
+                                                    "__idata5_magic__",
+                                                    false, false, true);
+                       first_thunk_address = myh->root.u.def.value + 
+                         sec->output_section->vma + 
+                           sec->output_offset - 
+                             pe_data(output_bfd)->pe_opthdr.ImageBase;
+                       
+                       idata5offset = myh->root.u.def.value;
+                       myh = coff_link_hash_lookup (coff_hash_table (info),
+                                                    "__idata6_magic__",
+                                                    false, false, true);
+                       
+                       thunk_size = myh->root.u.def.value - idata5offset;
+                       myh = coff_link_hash_lookup (coff_hash_table (info),
+                                                    "__idata4_magic__",
+                                                    false, false, true);
+                       import_table_size = myh->root.u.def.value;
+                     }
+                 }
+             }
+
+           rstat = _bfd_relocate_contents (howto,
+                             input_bfd, 
+                             val - 
+                             pe_data(output_bfd)->pe_opthdr.ImageBase,
+                             loc);
+         }
          break;
 
-       case IMAGE_REL_PPC_ADDR16:
        case IMAGE_REL_PPC_REL24:
+         DUMP_RELOC2(howto->name, rel);
+         val -= (input_section->output_section->vma
+                 + input_section->output_offset);
+
+         rstat = _bfd_relocate_contents (howto,
+                                         input_bfd, 
+                                         val, 
+                                         loc);
+         break;
+       case IMAGE_REL_PPC_ADDR16:
        case IMAGE_REL_PPC_ADDR24:
        case IMAGE_REL_PPC_ADDR32:
-       case IMAGE_REL_PPC_ADDR32NB:
-         rstat = _bfd_relocate_contents (ppc_coff_howto_table + r_type,
-                                         input_bfd, val, loc);
-         if (rstat == bfd_reloc_overflow)
-           overflow = true;
-         else if (rstat != bfd_reloc_ok)
-           abort ();
+         DUMP_RELOC2(howto->name, rel);
+         rstat = _bfd_relocate_contents (howto,
+                                         input_bfd, 
+                                         val, 
+                                         loc);
          break;
        }
 
-      if (overflow)
+      if ( info->base_file )
        {
-         const char *name;
-         char buf[SYMNMLEN + 1];
-
-         if (symndx == -1)
-           name = "*ABS*";
-         else if (h != NULL)
-           name = h->root.root.string;
-         else if (sym == NULL)
-           name = "*unknown*";
-         else if (sym->_n._n_n._n_zeroes == 0
-                  && sym->_n._n_n._n_offset != 0)
-           name = obj_coff_strings (input_bfd) + sym->_n._n_n._n_offset;
-         else
+         /* So if this is non pcrelative, and is referenced
+            to a section or a common symbol, then it needs a reloc */
+         if (sym && pe_data(output_bfd)->in_reloc_p(output_bfd, howto))
            {
-             strncpy (buf, sym->_n._n_name, SYMNMLEN);
-             buf[SYMNMLEN] = '\0';
-             name = buf;
+             /* relocation to a symbol in a section which
+                isn't absolute - we output the address here 
+                to a file */
+             bfd_vma addr = rel->r_vaddr 
+               - input_section->vma 
+               + input_section->output_offset 
+                 + input_section->output_section->vma;
+
+             if (coff_data(output_bfd)->pe)
+               {
+                 addr -= pe_data(output_bfd)->pe_opthdr.ImageBase;
+               }
+             fwrite (&addr, 1,4, (FILE *) info->base_file);
            }
+       }
 
-         if (! ((*info->callbacks->reloc_overflow)
-                (info, name, ppc_coff_howto_table[r_type].name, (bfd_vma) 0,
-                 input_bfd, input_section,
-                 rel->r_vaddr - input_section->vma)))
-           return false;
+      switch (rstat)
+       {
+       default:
+         abort ();
+       case bfd_reloc_ok:
+         break;
+       case bfd_reloc_overflow:
+         {
+           const char *name;
+           char buf[SYMNMLEN + 1];
+
+           if (symndx == -1)
+             name = "*ABS*";
+           else if (h != NULL)
+             name = h->root.root.root.string;
+           else if (sym == NULL)
+             name = "*unknown*";
+           else if (sym->_n._n_n._n_zeroes == 0
+                    && sym->_n._n_n._n_offset != 0)
+             name = obj_coff_strings (input_bfd) + sym->_n._n_n._n_offset;
+           else
+             {
+               strncpy (buf, sym->_n._n_name, SYMNMLEN);
+               buf[SYMNMLEN] = '\0';
+               name = buf;
+             }
+
+           if (! ((*info->callbacks->reloc_overflow)
+                  (info, name, howto->name, 
+                   (bfd_vma) 0, input_bfd,
+                   input_section, rel->r_vaddr - input_section->vma)))
+             {
+               return false;
+             }
+         }
        }
+
     }     
 
   return true;
 }
 
-\f
 
-/* Some really cheezy macros that can be turned on to test stderr :-) */
+#ifdef COFF_IMAGE_WITH_PE
 
-#ifdef DEBUG_RELOC
-#define UN_IMPL(x)                                           \
-{                                                            \
-   static int i;                                             \
-   if (i == 0)                                               \
-     {                                                       \
-       i = 1;                                                \
-       fprintf(stderr,"Unimplemented Relocation -- %s\n",x); \
-     }                                                       \
+long int global_toc_size = 4;
+
+bfd* bfd_of_toc_owner = 0;
+
+long int import_table_size;
+long int first_thunk_address;
+long int thunk_size;
+
+struct list_ele *head;
+struct list_ele *tail;
+
+static char *
+h1 = "\n\t\t\tTOC MAPPING\n\n";
+static char *
+h2 = " TOC    disassembly  Comments       Name\n";
+static char *
+h3 = " Offset  spelling                   (if present)\n";
+
+void
+dump_toc(vfile)
+     void *vfile;
+{
+  FILE *file = vfile;
+  struct list_ele *t;
+
+  fprintf(file, h1);
+  fprintf(file, h2);
+  fprintf(file, h3);
+
+  for(t = head; t != 0; t=t->next)
+    {
+      char *cat;
+
+      if (t->cat == priv)
+       cat = "private       ";
+      else if (t->cat == pub)
+       cat = "public        ";
+      else if (t->cat == data)
+       cat = "data-in-toc   ";
+
+      if (t->offset > global_toc_size)
+       {
+         if (t->offset <= global_toc_size + thunk_size)
+           cat = "IAT reference ";
+         else
+           {
+             fprintf(file,
+                     "**** global_toc_size %ld(%lx), thunk_size %ld(%lx)\n",
+                     global_toc_size, global_toc_size, thunk_size, thunk_size);
+             cat = "Out of bounds!";
+           }
+       }
+
+      fprintf(file,
+             " %04lx    (%d)", (unsigned long) t->offset, t->offset - 32768);
+      fprintf(file,
+             "    %s %s\n",
+             cat, t->name);
+
+    }
+
+  fprintf(file, "\n");
 }
 
-#define DUMP_RELOC(n,r)                              \
-{                                                    \
-   fprintf(stderr,"%s sym %d, addr %d, addend %d\n", \
-          n, (*(r->sym_ptr_ptr))->name,             \
-          r->address, r->addend);                   \
+boolean
+ppc_allocate_toc_section (info) 
+     struct bfd_link_info *info;
+{
+  asection *s;
+  bfd_byte *foo;
+  static char test_char = '1';
+
+  if ( global_toc_size == 0 ) /* FIXME: does this get me in trouble? */
+    return true;
+
+  if (bfd_of_toc_owner == 0)
+    {
+      /* No toc owner? Something is very wrong. */
+      abort();
+    }
+
+  s = bfd_get_section_by_name ( bfd_of_toc_owner , TOC_SECTION_NAME);
+  if (s == NULL) 
+    {
+      /* No toc section? Something is very wrong. */
+      abort();
+    }
+
+  foo = (bfd_byte *) bfd_alloc(bfd_of_toc_owner, global_toc_size);
+  memset(foo, test_char, global_toc_size);
+
+  s->_raw_size = s->_cooked_size = global_toc_size;
+  s->contents = foo;
+
+  return true;
 }
 
-#define DUMP_RELOC2(n,r)                     \
-{                                            \
-   fprintf(stderr,"%s sym %d, r_vaddr %d\n", \
-          n, r->r_symndx, r->r_vaddr);      \
+boolean
+ppc_process_before_allocation (abfd, info)
+     bfd *abfd;
+     struct bfd_link_info *info;
+{
+  asection *sec;
+  struct internal_reloc *i, *rel;
+
+  /* here we have a bfd that is to be included on the link. We have a hook
+     to do reloc rummaging, before section sizes are nailed down. */
+
+  _bfd_coff_get_external_symbols(abfd);
+
+  /* rummage around all the relocs and map the toc */
+  sec = abfd->sections;
+
+  if (sec == 0)
+    {
+      return true;
+    }
+
+  for (; sec != 0; sec = sec->next)
+  {
+    if (sec->reloc_count == 0) 
+      continue;
+
+    /* load the relocs */
+    /* FIXME: there may be a storage leak here */
+    i=_bfd_coff_read_internal_relocs(abfd,sec,1,0,0,0);
+    
+    if (i == 0)
+      abort();
+
+    for (rel=i;rel<i+sec->reloc_count;++rel) 
+      {
+       unsigned short r_type  = EXTRACT_TYPE (rel->r_type);
+       unsigned short r_flags = EXTRACT_FLAGS(rel->r_type);
+       boolean ok = true;
+
+       DUMP_RELOC2(ppc_coff_howto_table[r_type].name, rel);
+
+       switch(r_type) 
+         {
+         case IMAGE_REL_PPC_TOCREL16:
+           /* if TOCDEFN is on, ignore as someone else has allocated the
+              toc entry */
+           if ( (r_flags & IMAGE_REL_PPC_TOCDEFN) != IMAGE_REL_PPC_TOCDEFN )
+             ok = ppc_record_toc_entry(abfd, info, sec, 
+                                       rel->r_symndx, default_toc);
+           if (!ok)
+             return false;
+           break;
+         case IMAGE_REL_PPC_IMGLUE:
+           ppc_mark_symbol_as_glue(abfd, rel->r_symndx, rel);
+           break;
+         default:
+           break;
+         }
+      }
+  }
+
+  return true;
 }
 
-#else
-#define UN_IMPL(x)
-#define DUMP_RELOC(n,r)
-#define DUMP_RELOC2(n,r)
 #endif
 
 
@@ -938,6 +1785,8 @@ ppc_refhi_reloc (abfd,
   return bfd_reloc_undefined;
 }
 
+#if 0
+
 static bfd_reloc_status_type
 ppc_reflo_reloc (abfd,
                 reloc_entry,
@@ -963,6 +1812,8 @@ ppc_reflo_reloc (abfd,
   return bfd_reloc_undefined;
 }
 
+#endif
+
 static bfd_reloc_status_type
 ppc_pair_reloc (abfd,
                reloc_entry,
@@ -1016,6 +1867,8 @@ ppc_toc16_reloc (abfd,
   return bfd_reloc_ok;
 }
 
+#if 0
+
 /* ADDR32NB : 32 bit address relative to the virtual origin.         */
 /*            (On the alpha, this is always a linker generated thunk)*/
 /*            (i.e. 32bit addr relative to the image base)           */
@@ -1044,6 +1897,8 @@ ppc_addr32nb_reloc (abfd,
   return bfd_reloc_ok;
 }
 
+#endif
+
 static bfd_reloc_status_type
 ppc_secrel_reloc (abfd,
                  reloc_entry,
@@ -1148,74 +2003,54 @@ ppc_coff_rtype2howto (relent, internal)
      For now, we just strip this stuff to find the type, and ignore it other
      than that.
   */
-
+  reloc_howto_type *howto;
   unsigned short r_type  = EXTRACT_TYPE (internal->r_type);
   unsigned short r_flags = EXTRACT_FLAGS(internal->r_type);
   unsigned short junk    = EXTRACT_JUNK (internal->r_type);
 
   /* the masking process only slices off the bottom byte for r_type. */
   if ( r_type > MAX_RELOC_INDEX ) 
-    {
-      fprintf(stderr, 
-             "ppc_coff_rtype2howto: reloc index %d out of range [%d, %d]\n",
-             internal->r_type, 0, MAX_RELOC_INDEX);
-      abort();
-    }
+    abort();
 
   /* check for absolute crap */
   if ( junk != 0 )
-    {
-      fprintf(stderr, 
-             "ppc_coff_rtype2howto: reloc index %d contains junk %d\n",
-             internal->r_type, junk);
-      abort();
-    }
-
-#ifdef DEBUG_RELOC
-  /* now examine flags */
-  if (r_flags != 0) 
-    {
-      fprintf (stderr, "Reloc with flags found!");
-      if ( r_flags & IMAGE_REL_PPC_NEG ) 
-       fprintf (stderr, " NEG");
-      if ( r_flags & IMAGE_REL_PPC_BRTAKEN )
-       fprintf (stderr, " BRTAKEN");
-      if ( r_flags & IMAGE_REL_PPC_BRNTAKEN )
-       fprintf (stderr, " BRNTAKEN");
-      if ( r_flags & IMAGE_REL_PPC_TOCDEFN )
-       fprintf (stderr, " TOCDEFN");
-      fprintf(stderr, "\n");
-    }
-#endif
+    abort();
 
   switch(r_type) 
     {
     case IMAGE_REL_PPC_ADDR16:
     case IMAGE_REL_PPC_REL24:
     case IMAGE_REL_PPC_ADDR24:
-    case IMAGE_REL_PPC_TOCREL16:
     case IMAGE_REL_PPC_ADDR32:
     case IMAGE_REL_PPC_IFGLUE:
     case IMAGE_REL_PPC_ADDR32NB:
     case IMAGE_REL_PPC_SECTION:
     case IMAGE_REL_PPC_SECREL:
       DUMP_RELOC2(ppc_coff_howto_table[r_type].name, internal);
+      howto = ppc_coff_howto_table + r_type;
       break;
     case IMAGE_REL_PPC_IMGLUE:
       DUMP_RELOC2(ppc_coff_howto_table[r_type].name, internal);
-      /* IMGLUE relocs have big numbers in them. Don't know what for yet. */
-      internal->r_vaddr = 0; /* make it zero for now */
+      howto = ppc_coff_howto_table + r_type;
+      break;
+    case IMAGE_REL_PPC_TOCREL16:
+      DUMP_RELOC2(ppc_coff_howto_table[r_type].name, internal);
+      if (r_flags & IMAGE_REL_PPC_TOCDEFN)
+       howto = ppc_coff_howto_table + IMAGE_REL_PPC_TOCREL16_DEFN;
+      else
+       howto = ppc_coff_howto_table + IMAGE_REL_PPC_TOCREL16;
       break;
     default:
       fprintf(stderr, 
              "Warning: Unsupported reloc %s [%d] used -- it may not work.\n",
              ppc_coff_howto_table[r_type].name,
              r_type);
+      howto = ppc_coff_howto_table + r_type;      
       break;
     }
-
-  relent->howto = ppc_coff_howto_table + r_type;
-
+  
+  relent->howto = howto;
+  
 }
 
 static reloc_howto_type *
@@ -1246,103 +2081,80 @@ coff_ppc_rtype_to_howto (abfd, sec, rel, h, sym, addendp)
 
   /* the masking process only slices off the bottom byte for r_type. */
   if ( r_type > MAX_RELOC_INDEX ) 
-    {
-      fprintf(stderr, 
-             "coff_ppc_rtype_to_howto: index %d out of range [%d, %d]\n",
-             r_type, 0, MAX_RELOC_INDEX);
-      abort();
-    }
-
+    abort();
+  
   /* check for absolute crap */
   if ( junk != 0 )
-    {
-      fprintf(stderr, 
-             "coff_ppc_rtype_to_howto: reloc index %d contains junk %d\n",
-             rel->r_type, junk);
-      abort();
-    }
-
-#ifdef DEBUG_RELOC
-  /* now examine flags */
-  if (r_flags != 0) 
-    {
-      fprintf (stderr, "Reloc with flags found!");
-      if ( r_flags & IMAGE_REL_PPC_NEG ) 
-       fprintf (stderr, " NEG");
-      if ( r_flags & IMAGE_REL_PPC_BRTAKEN )
-       fprintf (stderr, " BRTAKEN");
-      if ( r_flags & IMAGE_REL_PPC_BRNTAKEN )
-       fprintf (stderr, " BRNTAKEN");
-      if ( r_flags & IMAGE_REL_PPC_TOCDEFN )
-       fprintf (stderr, " TOCDEFN");
-      fprintf(stderr, "\n");
-    }
-#endif
-
+    abort();
+    
   switch(r_type) 
     {
     case IMAGE_REL_PPC_ADDR32NB:
       DUMP_RELOC2(ppc_coff_howto_table[r_type].name, rel);
       *addendp -= pe_data(sec->output_section->owner)->pe_opthdr.ImageBase;
+      howto = ppc_coff_howto_table + r_type;
+      break;
+    case IMAGE_REL_PPC_TOCREL16:
+      DUMP_RELOC2(ppc_coff_howto_table[r_type].name, rel);
+      if (r_flags & IMAGE_REL_PPC_TOCDEFN)
+       howto = ppc_coff_howto_table + IMAGE_REL_PPC_TOCREL16_DEFN;
+      else
+       howto = ppc_coff_howto_table + IMAGE_REL_PPC_TOCREL16;
       break;
     case IMAGE_REL_PPC_ADDR16:
     case IMAGE_REL_PPC_REL24:
     case IMAGE_REL_PPC_ADDR24:
-    case IMAGE_REL_PPC_TOCREL16:
     case IMAGE_REL_PPC_ADDR32:
     case IMAGE_REL_PPC_IFGLUE:
     case IMAGE_REL_PPC_SECTION:
     case IMAGE_REL_PPC_SECREL:
       DUMP_RELOC2(ppc_coff_howto_table[r_type].name, rel);
+      howto = ppc_coff_howto_table + r_type;
       break;
     case IMAGE_REL_PPC_IMGLUE:
       DUMP_RELOC2(ppc_coff_howto_table[r_type].name, rel);
-      /* IMGLUE relocs have big numbers in them. Don't know what for yet. */
-      rel->r_vaddr = 0; /* make it zero for now */
+      howto = ppc_coff_howto_table + r_type;
       break;
     default:
       fprintf(stderr, 
              "Warning: Unsupported reloc %s [%d] used -- it may not work.\n",
              ppc_coff_howto_table[r_type].name,
              r_type);
+      howto = ppc_coff_howto_table + r_type;
       break;
     }
-
-  howto = ppc_coff_howto_table + r_type;
+  
   return howto;
 }
 
 
 /* a cheesy little macro to make the code a little more readable */
 #define HOW2MAP(bfd_rtype,ppc_rtype)  \
         case bfd_rtype: return &ppc_coff_howto_table[ppc_rtype]
+ case bfd_rtype: return &ppc_coff_howto_table[ppc_rtype]
 
 static reloc_howto_type *ppc_coff_reloc_type_lookup
-  PARAMS ((bfd *, bfd_reloc_code_real_type));
+PARAMS ((bfd *, bfd_reloc_code_real_type));
 
 static reloc_howto_type *
 ppc_coff_reloc_type_lookup (abfd, code)
      bfd *abfd;
      bfd_reloc_code_real_type code;
 {
-
-#ifdef DEBUG_RELOC
-  fprintf(stderr, "ppc_coff_reloc_type_lookup for %s\n",
-                   bfd_get_reloc_code_name(code));
-#endif
-
   switch (code)
     {
+      HOW2MAP(BFD_RELOC_32_GOTOFF,    IMAGE_REL_PPC_IMGLUE);
       HOW2MAP(BFD_RELOC_16_GOT_PCREL, IMAGE_REL_PPC_IFGLUE);
       HOW2MAP(BFD_RELOC_16,           IMAGE_REL_PPC_ADDR16);
       HOW2MAP(BFD_RELOC_PPC_B26,      IMAGE_REL_PPC_REL24);
       HOW2MAP(BFD_RELOC_PPC_BA26,     IMAGE_REL_PPC_ADDR24);
       HOW2MAP(BFD_RELOC_PPC_TOC16,    IMAGE_REL_PPC_TOCREL16);
+      HOW2MAP(BFD_RELOC_16_GOTOFF,    IMAGE_REL_PPC_TOCREL16_DEFN);
       HOW2MAP(BFD_RELOC_32,           IMAGE_REL_PPC_ADDR32);
-      default: return NULL;
+      HOW2MAP(BFD_RELOC_RVA,          IMAGE_REL_PPC_ADDR32NB);
+    default: 
+      return NULL;
     }
-
-  return NULL;
+  /*NOTREACHED*/
 }
 
 #undef HOW2MAP
@@ -1352,18 +2164,630 @@ ppc_coff_reloc_type_lookup (abfd, code)
 
 #define RTYPE2HOWTO(cache_ptr, dst)  ppc_coff_rtype2howto (cache_ptr, dst)
 
-/* We use the special COFF backend linker.  */
-/* #define coff_relocate_section        _bfd_coff_generic_relocate_section */
+#ifndef COFF_IMAGE_WITH_PE
+static void
+ppc_coff_swap_sym_in_hook ();
+#endif
+
+/* We use the special COFF backend linker, with our own special touch.  */
+
 #define coff_bfd_reloc_type_lookup   ppc_coff_reloc_type_lookup
 #define coff_rtype_to_howto          coff_ppc_rtype_to_howto
 #define coff_relocate_section        coff_ppc_relocate_section
+#define coff_bfd_final_link          ppc_bfd_coff_final_link 
+
+#ifndef COFF_IMAGE_WITH_PE
+#define coff_swap_sym_in_hook        ppc_coff_swap_sym_in_hook
+#endif
 
 #define SELECT_RELOC(internal, howto) {internal.r_type=howto->type;}
 
 #define COFF_PAGE_SIZE                       0x1000
 
+#define POWERPC_LE_PE
+
 #include "coffcode.h"
 
+\f
+
+#ifndef COFF_IMAGE_WITH_PE
+/* FIXME:
+   What we're trying to do here is allocate a toc section (early), and attach 
+   it to the last bfd to be processed. This avoids the problem of having a toc
+   written out before all files have been processed. This code allocates
+   a toc section for every file, and records the last one seen. There are
+   at least two problems with this approach:
+   1. We allocate whole bunches of toc sections that are ignored, but at
+      at least we will not allocate a toc if no .toc is present.
+   2. It's not clear to me that being the last bfd read necessarily means
+      that you are the last bfd closed.
+   3. Doing it on a "swap in" hook depends on when the "swap in" is called,
+      and how often, etc. It's not clear to me that there isn't a hole here.
+*/
+
+static void
+ppc_coff_swap_sym_in_hook (abfd, ext1, in1)
+     bfd            *abfd;
+     PTR ext1;
+     PTR in1;
+{
+  struct internal_syment      *in = (struct internal_syment *)in1;
+
+  if (bfd_of_toc_owner != 0) /* we already have a toc, so go home */
+    return;
+
+  if (strcmp(in->_n._n_name, ".toc") == 0)
+    {
+      flagword flags;
+      register asection *s;
+
+      s = bfd_get_section_by_name ( abfd , TOC_SECTION_NAME);
+      if (s != NULL) 
+       {
+         return;
+       }
+
+      flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY ;
+
+      s = bfd_make_section (abfd, TOC_SECTION_NAME);
+
+      if (s == NULL
+         || !bfd_set_section_flags (abfd, s, flags)
+         || !bfd_set_section_alignment (abfd, s, 2))
+       {
+         /* FIXME: set appropriate bfd error */
+         abort();
+       }
+
+      /* save the bfd for later allocation */
+      bfd_of_toc_owner = abfd;
+    }
+
+  return;
+}
+#endif
+
+boolean
+ppc_bfd_coff_final_link ();
+
+#ifndef COFF_IMAGE_WITH_PE
+
+static boolean
+ppc_do_last(abfd)
+     bfd *abfd;
+{
+  if (abfd == bfd_of_toc_owner)
+    return true;
+  else
+    return false;
+}
+
+static bfd *
+ppc_get_last()
+{
+  return bfd_of_toc_owner;
+}
+
+/* this piece of machinery exists only to guarantee that the bfd that holds
+   the toc section is written last. 
+
+   This does depend on bfd_make_section attaching a new section to the
+   end of the section list for the bfd. 
+
+   This is otherwise intended to be functionally the same as 
+   cofflink.c:_bfd_coff_final_link(). It is specifically different only 
+   where the POWERPC_LE_PE macro modifies the code. It is left in as a 
+   precise form of comment. krk@cygnus.com
+*/
+#define POWERPC_LE_PE
+
+
+/* Do the final link step.  */
+
+boolean
+ppc_bfd_coff_final_link (abfd, info)
+     bfd *abfd;
+     struct bfd_link_info *info;
+{
+  bfd_size_type symesz;
+  struct coff_final_link_info finfo;
+  boolean debug_merge_allocated;
+  asection *o;
+  struct bfd_link_order *p;
+  size_t max_sym_count;
+  size_t max_lineno_count;
+  size_t max_reloc_count;
+  size_t max_output_reloc_count;
+  size_t max_contents_size;
+  file_ptr rel_filepos;
+  unsigned int relsz;
+  file_ptr line_filepos;
+  unsigned int linesz;
+  bfd *sub;
+  bfd_byte *external_relocs = NULL;
+  char strbuf[STRING_SIZE_SIZE];
+
+  symesz = bfd_coff_symesz (abfd);
+
+  finfo.info = info;
+  finfo.output_bfd = abfd;
+  finfo.strtab = NULL;
+  finfo.section_info = NULL;
+  finfo.last_file_index = -1;
+  finfo.last_bf_index = -1;
+  finfo.internal_syms = NULL;
+  finfo.sec_ptrs = NULL;
+  finfo.sym_indices = NULL;
+  finfo.outsyms = NULL;
+  finfo.linenos = NULL;
+  finfo.contents = NULL;
+  finfo.external_relocs = NULL;
+  finfo.internal_relocs = NULL;
+  debug_merge_allocated = false;
+
+  coff_data (abfd)->link_info = info;
+
+  finfo.strtab = _bfd_stringtab_init ();
+  if (finfo.strtab == NULL)
+    goto error_return;
+
+  if (! coff_debug_merge_hash_table_init (&finfo.debug_merge))
+    goto error_return;
+  debug_merge_allocated = true;
+
+  /* Compute the file positions for all the sections.  */
+  if (! abfd->output_has_begun)
+    {
+      if (! bfd_coff_compute_section_file_positions (abfd))
+       return false;
+    }
+
+  /* Count the line numbers and relocation entries required for the
+     output file.  Set the file positions for the relocs.  */
+  rel_filepos = obj_relocbase (abfd);
+  relsz = bfd_coff_relsz (abfd);
+  max_contents_size = 0;
+  max_lineno_count = 0;
+  max_reloc_count = 0;
+
+  for (o = abfd->sections; o != NULL; o = o->next)
+    {
+      o->reloc_count = 0;
+      o->lineno_count = 0;
+      for (p = o->link_order_head; p != NULL; p = p->next)
+       {
+
+         if (p->type == bfd_indirect_link_order)
+           {
+             asection *sec;
+
+             sec = p->u.indirect.section;
+
+             /* Mark all sections which are to be included in the
+                link.  This will normally be every section.  We need
+                to do this so that we can identify any sections which
+                the linker has decided to not include.  */
+             sec->linker_mark = true;
+
+             if (info->strip == strip_none
+                 || info->strip == strip_some)
+               o->lineno_count += sec->lineno_count;
+
+             if (info->relocateable)
+               o->reloc_count += sec->reloc_count;
+
+             if (sec->_raw_size > max_contents_size)
+               max_contents_size = sec->_raw_size;
+             if (sec->lineno_count > max_lineno_count)
+               max_lineno_count = sec->lineno_count;
+             if (sec->reloc_count > max_reloc_count)
+               max_reloc_count = sec->reloc_count;
+           }
+         else if (info->relocateable
+                  && (p->type == bfd_section_reloc_link_order
+                      || p->type == bfd_symbol_reloc_link_order))
+           ++o->reloc_count;
+       }
+      if (o->reloc_count == 0)
+       o->rel_filepos = 0;
+      else
+       {
+         o->flags |= SEC_RELOC;
+         o->rel_filepos = rel_filepos;
+         rel_filepos += o->reloc_count * relsz;
+       }
+    }
+
+  /* If doing a relocateable link, allocate space for the pointers we
+     need to keep.  */
+  if (info->relocateable)
+    {
+      unsigned int i;
+
+      /* We use section_count + 1, rather than section_count, because
+         the target_index fields are 1 based.  */
+      finfo.section_info =
+       ((struct coff_link_section_info *)
+        bfd_malloc ((abfd->section_count + 1)
+                    * sizeof (struct coff_link_section_info)));
+      if (finfo.section_info == NULL)
+       goto error_return;
+      for (i = 0; i <= abfd->section_count; i++)
+       {
+         finfo.section_info[i].relocs = NULL;
+         finfo.section_info[i].rel_hashes = NULL;
+       }
+    }
+
+  /* We now know the size of the relocs, so we can determine the file
+     positions of the line numbers.  */
+  line_filepos = rel_filepos;
+  linesz = bfd_coff_linesz (abfd);
+  max_output_reloc_count = 0;
+  for (o = abfd->sections; o != NULL; o = o->next)
+    {
+      if (o->lineno_count == 0)
+       o->line_filepos = 0;
+      else
+       {
+         o->line_filepos = line_filepos;
+         line_filepos += o->lineno_count * linesz;
+       }
+
+      if (o->reloc_count != 0)
+       {
+         /* We don't know the indices of global symbols until we have
+             written out all the local symbols.  For each section in
+             the output file, we keep an array of pointers to hash
+             table entries.  Each entry in the array corresponds to a
+             reloc.  When we find a reloc against a global symbol, we
+             set the corresponding entry in this array so that we can
+             fix up the symbol index after we have written out all the
+             local symbols.
+
+            Because of this problem, we also keep the relocs in
+            memory until the end of the link.  This wastes memory,
+            but only when doing a relocateable link, which is not the
+            common case.  */
+         BFD_ASSERT (info->relocateable);
+         finfo.section_info[o->target_index].relocs =
+           ((struct internal_reloc *)
+            bfd_malloc (o->reloc_count * sizeof (struct internal_reloc)));
+         finfo.section_info[o->target_index].rel_hashes =
+           ((struct coff_link_hash_entry **)
+            bfd_malloc (o->reloc_count
+                    * sizeof (struct coff_link_hash_entry *)));
+         if (finfo.section_info[o->target_index].relocs == NULL
+             || finfo.section_info[o->target_index].rel_hashes == NULL)
+           goto error_return;
+
+         if (o->reloc_count > max_output_reloc_count)
+           max_output_reloc_count = o->reloc_count;
+       }
+
+      /* Reset the reloc and lineno counts, so that we can use them to
+        count the number of entries we have output so far.  */
+      o->reloc_count = 0;
+      o->lineno_count = 0;
+    }
+
+  obj_sym_filepos (abfd) = line_filepos;
+
+  /* Figure out the largest number of symbols in an input BFD.  Take
+     the opportunity to clear the output_has_begun fields of all the
+     input BFD's.  */
+  max_sym_count = 0;
+  for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
+    {
+      size_t sz;
+
+      sub->output_has_begun = false;
+      sz = obj_raw_syment_count (sub);
+      if (sz > max_sym_count)
+       max_sym_count = sz;
+    }
+
+  /* Allocate some buffers used while linking.  */
+  finfo.internal_syms = ((struct internal_syment *)
+                        bfd_malloc (max_sym_count
+                                    * sizeof (struct internal_syment)));
+  finfo.sec_ptrs = (asection **) bfd_malloc (max_sym_count
+                                            * sizeof (asection *));
+  finfo.sym_indices = (long *) bfd_malloc (max_sym_count * sizeof (long));
+  finfo.outsyms = ((bfd_byte *)
+                  bfd_malloc ((size_t) ((max_sym_count + 1) * symesz)));
+  finfo.linenos = (bfd_byte *) bfd_malloc (max_lineno_count
+                                      * bfd_coff_linesz (abfd));
+  finfo.contents = (bfd_byte *) bfd_malloc (max_contents_size);
+  finfo.external_relocs = (bfd_byte *) bfd_malloc (max_reloc_count * relsz);
+  if (! info->relocateable)
+    finfo.internal_relocs = ((struct internal_reloc *)
+                            bfd_malloc (max_reloc_count
+                                        * sizeof (struct internal_reloc)));
+  if ((finfo.internal_syms == NULL && max_sym_count > 0)
+      || (finfo.sec_ptrs == NULL && max_sym_count > 0)
+      || (finfo.sym_indices == NULL && max_sym_count > 0)
+      || finfo.outsyms == NULL
+      || (finfo.linenos == NULL && max_lineno_count > 0)
+      || (finfo.contents == NULL && max_contents_size > 0)
+      || (finfo.external_relocs == NULL && max_reloc_count > 0)
+      || (! info->relocateable
+         && finfo.internal_relocs == NULL
+         && max_reloc_count > 0))
+    goto error_return;
+
+  /* We now know the position of everything in the file, except that
+     we don't know the size of the symbol table and therefore we don't
+     know where the string table starts.  We just build the string
+     table in memory as we go along.  We process all the relocations
+     for a single input file at once.  */
+  obj_raw_syment_count (abfd) = 0;
+
+  if (coff_backend_info (abfd)->_bfd_coff_start_final_link)
+    {
+      if (! bfd_coff_start_final_link (abfd, info))
+       goto error_return;
+    }
+
+  for (o = abfd->sections; o != NULL; o = o->next)
+    {
+      for (p = o->link_order_head; p != NULL; p = p->next)
+       {
+         if (p->type == bfd_indirect_link_order
+             && (bfd_get_flavour (p->u.indirect.section->owner)
+                 == bfd_target_coff_flavour))
+           {
+             sub = p->u.indirect.section->owner;
+#ifdef POWERPC_LE_PE
+             if (! sub->output_has_begun && !ppc_do_last(sub))
+#else
+             if (! sub->output_has_begun)
+#endif
+               {
+                 if (! _bfd_coff_link_input_bfd (&finfo, sub))
+                   goto error_return;
+                 sub->output_has_begun = true;
+               }
+           }
+         else if (p->type == bfd_section_reloc_link_order
+                  || p->type == bfd_symbol_reloc_link_order)
+           {
+             if (! _bfd_coff_reloc_link_order (abfd, &finfo, o, p))
+               goto error_return;
+           }
+         else
+           {
+             if (! _bfd_default_link_order (abfd, info, o, p))
+               goto error_return;
+           }
+       }
+    }
+
+#ifdef POWERPC_LE_PE
+  {
+    extern bfd* ppc_get_last();
+    bfd* last_one = ppc_get_last();
+    if (last_one)
+      {
+       if (! _bfd_coff_link_input_bfd (&finfo, last_one))
+         goto error_return;
+      }
+    last_one->output_has_begun = true;
+  }
+#endif
+
+  /* Free up the buffers used by _bfd_coff_link_input_bfd.  */
+
+  coff_debug_merge_hash_table_free (&finfo.debug_merge);
+  debug_merge_allocated = false;
+
+  if (finfo.internal_syms != NULL)
+    {
+      free (finfo.internal_syms);
+      finfo.internal_syms = NULL;
+    }
+  if (finfo.sec_ptrs != NULL)
+    {
+      free (finfo.sec_ptrs);
+      finfo.sec_ptrs = NULL;
+    }
+  if (finfo.sym_indices != NULL)
+    {
+      free (finfo.sym_indices);
+      finfo.sym_indices = NULL;
+    }
+  if (finfo.linenos != NULL)
+    {
+      free (finfo.linenos);
+      finfo.linenos = NULL;
+    }
+  if (finfo.contents != NULL)
+    {
+      free (finfo.contents);
+      finfo.contents = NULL;
+    }
+  if (finfo.external_relocs != NULL)
+    {
+      free (finfo.external_relocs);
+      finfo.external_relocs = NULL;
+    }
+  if (finfo.internal_relocs != NULL)
+    {
+      free (finfo.internal_relocs);
+      finfo.internal_relocs = NULL;
+    }
+
+  /* The value of the last C_FILE symbol is supposed to be the symbol
+     index of the first external symbol.  Write it out again if
+     necessary.  */
+  if (finfo.last_file_index != -1
+      && (unsigned int) finfo.last_file.n_value != obj_raw_syment_count (abfd))
+    {
+      finfo.last_file.n_value = obj_raw_syment_count (abfd);
+      bfd_coff_swap_sym_out (abfd, (PTR) &finfo.last_file,
+                            (PTR) finfo.outsyms);
+      if (bfd_seek (abfd,
+                   (obj_sym_filepos (abfd)
+                    + finfo.last_file_index * symesz),
+                   SEEK_SET) != 0
+         || bfd_write (finfo.outsyms, symesz, 1, abfd) != symesz)
+       return false;
+    }
+
+  /* Write out the global symbols.  */
+  finfo.failed = false;
+  coff_link_hash_traverse (coff_hash_table (info), _bfd_coff_write_global_sym,
+                          (PTR) &finfo);
+  if (finfo.failed)
+    goto error_return;
+
+  /* The outsyms buffer is used by _bfd_coff_write_global_sym.  */
+  if (finfo.outsyms != NULL)
+    {
+      free (finfo.outsyms);
+      finfo.outsyms = NULL;
+    }
+
+  if (info->relocateable)
+    {
+      /* Now that we have written out all the global symbols, we know
+        the symbol indices to use for relocs against them, and we can
+        finally write out the relocs.  */
+      external_relocs = ((bfd_byte *)
+                        bfd_malloc (max_output_reloc_count * relsz));
+      if (external_relocs == NULL)
+       goto error_return;
+
+      for (o = abfd->sections; o != NULL; o = o->next)
+       {
+         struct internal_reloc *irel;
+         struct internal_reloc *irelend;
+         struct coff_link_hash_entry **rel_hash;
+         bfd_byte *erel;
+
+         if (o->reloc_count == 0)
+           continue;
+
+         irel = finfo.section_info[o->target_index].relocs;
+         irelend = irel + o->reloc_count;
+         rel_hash = finfo.section_info[o->target_index].rel_hashes;
+         erel = external_relocs;
+         for (; irel < irelend; irel++, rel_hash++, erel += relsz)
+           {
+             if (*rel_hash != NULL)
+               {
+                 BFD_ASSERT ((*rel_hash)->indx >= 0);
+                 irel->r_symndx = (*rel_hash)->indx;
+               }
+             bfd_coff_swap_reloc_out (abfd, (PTR) irel, (PTR) erel);
+           }
+
+         if (bfd_seek (abfd, o->rel_filepos, SEEK_SET) != 0
+             || bfd_write ((PTR) external_relocs, relsz, o->reloc_count,
+                           abfd) != relsz * o->reloc_count)
+           goto error_return;
+       }
+
+      free (external_relocs);
+      external_relocs = NULL;
+    }
+
+  /* Free up the section information.  */
+  if (finfo.section_info != NULL)
+    {
+      unsigned int i;
+
+      for (i = 0; i < abfd->section_count; i++)
+       {
+         if (finfo.section_info[i].relocs != NULL)
+           free (finfo.section_info[i].relocs);
+         if (finfo.section_info[i].rel_hashes != NULL)
+           free (finfo.section_info[i].rel_hashes);
+       }
+      free (finfo.section_info);
+      finfo.section_info = NULL;
+    }
+
+  /* If we have optimized stabs strings, output them.  */
+  if (coff_hash_table (info)->stab_info != NULL)
+    {
+      if (! _bfd_write_stab_strings (abfd, &coff_hash_table (info)->stab_info))
+       return false;
+    }
+
+  /* Write out the string table.  */
+  if (obj_raw_syment_count (abfd) != 0)
+    {
+      if (bfd_seek (abfd,
+                   (obj_sym_filepos (abfd)
+                    + obj_raw_syment_count (abfd) * symesz),
+                   SEEK_SET) != 0)
+       return false;
+
+#if STRING_SIZE_SIZE == 4
+      bfd_h_put_32 (abfd,
+                   _bfd_stringtab_size (finfo.strtab) + STRING_SIZE_SIZE,
+                   (bfd_byte *) strbuf);
+#else
+ #error Change bfd_h_put_32
+#endif
+
+      if (bfd_write (strbuf, 1, STRING_SIZE_SIZE, abfd) != STRING_SIZE_SIZE)
+       return false;
+
+      if (! _bfd_stringtab_emit (abfd, finfo.strtab))
+       return false;
+    }
+
+  _bfd_stringtab_free (finfo.strtab);
+
+  /* Setting bfd_get_symcount to 0 will cause write_object_contents to
+     not try to write out the symbols.  */
+  bfd_get_symcount (abfd) = 0;
+
+  return true;
+
+ error_return:
+  if (debug_merge_allocated)
+    coff_debug_merge_hash_table_free (&finfo.debug_merge);
+  if (finfo.strtab != NULL)
+    _bfd_stringtab_free (finfo.strtab);
+  if (finfo.section_info != NULL)
+    {
+      unsigned int i;
+
+      for (i = 0; i < abfd->section_count; i++)
+       {
+         if (finfo.section_info[i].relocs != NULL)
+           free (finfo.section_info[i].relocs);
+         if (finfo.section_info[i].rel_hashes != NULL)
+           free (finfo.section_info[i].rel_hashes);
+       }
+      free (finfo.section_info);
+    }
+  if (finfo.internal_syms != NULL)
+    free (finfo.internal_syms);
+  if (finfo.sec_ptrs != NULL)
+    free (finfo.sec_ptrs);
+  if (finfo.sym_indices != NULL)
+    free (finfo.sym_indices);
+  if (finfo.outsyms != NULL)
+    free (finfo.outsyms);
+  if (finfo.linenos != NULL)
+    free (finfo.linenos);
+  if (finfo.contents != NULL)
+    free (finfo.contents);
+  if (finfo.external_relocs != NULL)
+    free (finfo.external_relocs);
+  if (finfo.internal_relocs != NULL)
+    free (finfo.internal_relocs);
+  if (external_relocs != NULL)
+    free (external_relocs);
+  return false;
+}
+#endif
+\f
+
 /* The transfer vectors that lead the outside world to all of the above. */
 
 #ifdef TARGET_LITTLE_SYM
@@ -1372,32 +2796,39 @@ TARGET_LITTLE_SYM =
 {
   TARGET_LITTLE_NAME,          /* name or coff-arm-little */
   bfd_target_coff_flavour,
-  false,                       /* data byte order is little */
-  false,                       /* header byte order is little */
+  BFD_ENDIAN_LITTLE,           /* data byte order is little */
+  BFD_ENDIAN_LITTLE,           /* header byte order is little */
 
   (HAS_RELOC | EXEC_P |                /* FIXME: object flags */
    HAS_LINENO | HAS_DEBUG |
-   HAS_SYMS | HAS_LOCALS | WP_TEXT),
-
+   HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
+  
+#ifndef COFF_WITH_PE
   (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
+#else
+  (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC /* section flags */
+   | SEC_LINK_ONCE | SEC_LINK_DUPLICATES),
+#endif
+
   0,                           /* leading char */
   '/',                         /* ar_pad_char */
   15,                          /* ar_max_namelen??? FIXMEmgo */
 
   bfd_getl64, bfd_getl_signed_64, bfd_putl64,
-     bfd_getl32, bfd_getl_signed_32, bfd_putl32,
-     bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */
-  bfd_getl64, bfd_getl_signed_64, bfd_putl64,
-     bfd_getl32, bfd_getl_signed_32, bfd_putl32,
-     bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */
+  bfd_getl32, bfd_getl_signed_32, bfd_putl32,
+  bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */
 
+  bfd_getl64, bfd_getl_signed_64, bfd_putl64,
+  bfd_getl32, bfd_getl_signed_32, bfd_putl32,
+  bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */
+  
   {_bfd_dummy_target, coff_object_p,   /* bfd_check_format */
      bfd_generic_archive_p, /* _bfd_dummy_target */ coff_object_p },
   {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */
      bfd_false},
   {bfd_false, coff_write_object_contents,      /* bfd_write_contents */
      _bfd_write_archive_contents, bfd_false},
-
+  
   BFD_JUMP_TABLE_GENERIC (coff),
   BFD_JUMP_TABLE_COPY (coff),
   BFD_JUMP_TABLE_CORE (_bfd_nocore),
@@ -1407,7 +2838,7 @@ TARGET_LITTLE_SYM =
   BFD_JUMP_TABLE_WRITE (coff),
   BFD_JUMP_TABLE_LINK (coff),
   BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
-
+  
   COFF_SWAP_TABLE,
 };
 #endif
@@ -1418,24 +2849,31 @@ TARGET_BIG_SYM =
 {
   TARGET_BIG_NAME,
   bfd_target_coff_flavour,     
-  true,                                /* data byte order is big */
-  true,                                /* header byte order is big */
+  BFD_ENDIAN_BIG,              /* data byte order is big */
+  BFD_ENDIAN_BIG,              /* header byte order is big */
 
   (HAS_RELOC | EXEC_P |                /* FIXME: object flags */
    HAS_LINENO | HAS_DEBUG |
-   HAS_SYMS | HAS_LOCALS | WP_TEXT),
+   HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
 
+#ifndef COFF_WITH_PE
   (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
+#else
+  (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC /* section flags */
+   | SEC_LINK_ONCE | SEC_LINK_DUPLICATES),
+#endif
+
   0,                           /* leading char */
   '/',                         /* ar_pad_char */
   15,                          /* ar_max_namelen??? FIXMEmgo */
 
   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
-     bfd_getb32, bfd_getb_signed_32, bfd_putb32,
-     bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */
+  bfd_getb32, bfd_getb_signed_32, bfd_putb32,
+  bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */
+
   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
-     bfd_getb32, bfd_getb_signed_32, bfd_putb32,
-     bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */
+  bfd_getb32, bfd_getb_signed_32, bfd_putb32,
+  bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */
 
   {_bfd_dummy_target, coff_object_p,   /* bfd_check_format */
      bfd_generic_archive_p, /* _bfd_dummy_target */ coff_object_p },
@@ -1458,12 +2896,3 @@ TARGET_BIG_SYM =
 };
 
 #endif
-
-
-
-
-
-
-
-
-
This page took 0.049396 seconds and 4 git commands to generate.