Add support for mcore to dlltool.
[deliverable/binutils-gdb.git] / bfd / coff-ppc.c
index 379ef4e3406badfb0449238131016688c7ca95fb..cf4504479b51edfe0e1092dacfb335493c8fc8ba 100644 (file)
@@ -1,5 +1,6 @@
 /* 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, 97, 1998
+   Free Software Foundation, Inc.
 
    Original version pieced together by Kim Knuttila (krk@cygnus.com)
 
@@ -21,7 +22,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 /* Current State:
    - objdump works
@@ -34,8 +36,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 #include "bfd.h"
 #include "sysdep.h"
+
 #include "libbfd.h"
-#include "obstack.h"
 
 #include "coff/powerpc.h"
 #include "coff/internal.h"
@@ -50,6 +52,12 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 #include "libcoff.h"
 
+/* This file is compiled more than once, but we only compile the
+   final_link routine once.  */
+extern boolean ppc_bfd_coff_final_link
+  PARAMS ((bfd *, struct bfd_link_info *));
+extern void dump_toc PARAMS ((PTR));
+
 /* 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                   */
@@ -67,6 +75,33 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #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 */
 
@@ -81,20 +116,10 @@ struct ppc_coff_link_hash_entry
   bfd_vma toc_offset;               /* Our addition, as required */
   int symbol_is_glue;
   unsigned long int glue_insn;
-  char eye_catcher[8];
-};
 
-/* Need a 7 char string for an eye catcher */
-#define EYE "krkjunk"
+  HASH_CHECK_DCL
+};
 
-#define CHECK_EYE(addr) \
- if (strcmp(addr, EYE) != 0) \
-  { \
-    fprintf(stderr,\
-    "File %s, line %d, Hash check failure, bad eye %8s\n", \
-    __FILE__, __LINE__, addr); \
-    abort(); \
- }
 
 /* PE linker hash table.  */
 
@@ -106,6 +131,20 @@ struct ppc_coff_link_hash_table
 static struct bfd_hash_entry *ppc_coff_link_hash_newfunc
   PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *,
           const char *));
+static boolean ppc_coff_link_hash_table_init
+  PARAMS ((struct ppc_coff_link_hash_table *, bfd *,
+          struct bfd_hash_entry *(*) (struct bfd_hash_entry *,
+                                      struct bfd_hash_table *,
+                                      const char *)));
+static struct bfd_link_hash_table *ppc_coff_link_hash_table_create
+  PARAMS ((bfd *));
+static boolean coff_ppc_relocate_section
+  PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
+          struct internal_reloc *, struct internal_syment *, asection **));
+static reloc_howto_type *coff_ppc_rtype_to_howto
+  PARAMS ((bfd *, asection *, struct internal_reloc *,
+          struct coff_link_hash_entry *, struct internal_syment *,
+          bfd_vma *));
 
 /* Routine to create an entry in the link hash table.  */
 
@@ -139,7 +178,8 @@ ppc_coff_link_hash_newfunc (entry, table, string)
       SET_UNALLOCATED(ret->toc_offset);
       ret->symbol_is_glue = 0;
       ret->glue_insn = 0;
-      strcpy(ret->eye_catcher, EYE);
+
+      HASH_CHECK_INIT(ret);
     }
 
   return (struct bfd_hash_entry *) ret;
@@ -185,8 +225,8 @@ ppc_coff_link_hash_table_create (abfd)
 
 \f
 /* The nt loader points the toc register to &toc + 32768, in order to */
-/* use the complete range of a 16-bit displacement (I guess). We have */
-/* to adjust for this when we fix up loads displaced off the toc reg. */
+/* 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"
 
@@ -292,6 +332,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,
@@ -299,6 +340,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,
@@ -316,6 +358,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,
@@ -323,7 +366,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,
@@ -745,7 +788,7 @@ static reloc_howto_type ppc_coff_howto_table[] =
    if (i == 0)                                               \
      {                                                       \
        i = 1;                                                \
-       fprintf(stderr,"Unimplemented Relocation -- %s\n",x); \
+       fprintf(stderr,_("Unimplemented Relocation -- %s\n"),x); \
      }                                                       \
 }
 
@@ -782,6 +825,10 @@ static reloc_howto_type ppc_coff_howto_table[] =
 
 \f
 /* toc construction and management routines */
+
+/* This file is compiled twice, and these variables are defined in one
+   of the compilations.  FIXME: This is confusing and weird.  Also,
+   BFD should not use global variables.  */
 extern bfd* bfd_of_toc_owner;
 extern long int global_toc_size;
 
@@ -815,8 +862,11 @@ struct list_ele
 extern struct list_ele *head;
 extern struct list_ele *tail;
 
+static void record_toc
+  PARAMS ((asection *, int, enum ref_category, const char *));
+
 static void
-record_toc(toc_section, our_toc_offset, cat, name)
+record_toc (toc_section, our_toc_offset, cat, name)
      asection *toc_section;
      int our_toc_offset;
      enum ref_category cat;
@@ -824,7 +874,9 @@ record_toc(toc_section, our_toc_offset, cat, name)
 {
   /* add this entry to our toc addr-offset-name list */
   struct list_ele *t;
-  t = malloc(sizeof(struct list_ele));
+  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;
@@ -843,8 +895,15 @@ record_toc(toc_section, our_toc_offset, cat, name)
     }
 }
 
+#ifdef COFF_IMAGE_WITH_PE
+
+static boolean ppc_record_toc_entry
+  PARAMS ((bfd *, struct bfd_link_info *, asection *, int, enum toc_type));
+static void ppc_mark_symbol_as_glue
+  PARAMS ((bfd *, int, struct internal_reloc *));
+
 /* record a toc offset against a symbol */
-static int
+static boolean
 ppc_record_toc_entry(abfd, info, sec, sym, toc_kind)
      bfd *abfd;
      struct bfd_link_info *info;
@@ -852,15 +911,7 @@ ppc_record_toc_entry(abfd, info, sec, sym, toc_kind)
      int sym;
      enum toc_type toc_kind;
 {
-  bfd_byte *t;
-  bfd_byte *old_contents;
-  asection *s;
-  int element_size;
-  int data;
-  int offset;
   struct ppc_coff_link_hash_entry *h;
-  struct coff_symbol_struct *target;
-  int ret_val;
   const char *name;
 
   int *local_syms;
@@ -870,7 +921,7 @@ ppc_record_toc_entry(abfd, info, sec, sym, toc_kind)
   h = (struct ppc_coff_link_hash_entry *) (obj_coff_sym_hashes (abfd)[sym]);
   if (h != 0)
     {
-      CHECK_EYE(h->eye_catcher);
+      HASH_CHECK(h);
     }
 
   if (h == 0) 
@@ -878,7 +929,7 @@ ppc_record_toc_entry(abfd, info, sec, sym, toc_kind)
       local_syms = obj_coff_local_toc_table(abfd);
       if (local_syms == 0)
        {
-         int i;
+         unsigned int i;
          /* allocate a table */
          local_syms = 
            (int *) bfd_zalloc (abfd, 
@@ -895,31 +946,15 @@ ppc_record_toc_entry(abfd, info, sec, sym, toc_kind)
       if (IS_UNALLOCATED(local_syms[sym])) 
        {
          local_syms[sym] = global_toc_size;
-         ret_val = global_toc_size;
          global_toc_size += 4;
 
          /* The size must fit in a 16bit displacment */
-         if (global_toc_size >= 65535)
+         if (global_toc_size > 65535)
            {
-             fprintf(stderr,
-                     "Exceeded toc size of 65535\n");
-             abort();
+             (*_bfd_error_handler) (_("TOC overflow"));
+             bfd_set_error (bfd_error_file_too_big);
+             return false;
            }
-
-#ifdef TOC_DEBUG
-         fprintf(stderr,
-                 "Setting toc_offset for local sym %d to %d\n",
-                 sym, ret_val);
-#endif
-       }
-      else
-       {
-         ret_val = local_syms[sym];
-#ifdef TOC_DEBUG
-         fprintf(stderr,
-                 "toc_offset already set for local sym %d to %d\n",
-                 sym, ret_val);
-#endif
        }
     }
   else
@@ -931,151 +966,19 @@ ppc_record_toc_entry(abfd, info, sec, sym, toc_kind)
       if (IS_UNALLOCATED(h->toc_offset))
        {
          h->toc_offset = global_toc_size;
-         ret_val = global_toc_size;
          global_toc_size += 4;
 
          /* The size must fit in a 16bit displacment */
          if (global_toc_size >= 65535)
            {
-             fprintf(stderr,
-                     "Exceeded toc size of 65535\n");
-             abort();
-           }
-
-#ifdef TOC_DEBUG
-         fprintf(stderr,
-                 "Setting toc_offset for sym %d (%s) [h=%p] to %d\n",
-                 sym, name, h, ret_val);
-#endif
-       }
-      else
-       {
-         ret_val = h->toc_offset;
-#ifdef TOC_DEBUG
-         fprintf(stderr,
-                 "toc_offset already set for sym %d (%s) [h=%p] to %d\n",
-                 sym, name, h, ret_val);
-#endif
-       }
-    }
-
-  return ret_val;
-}
-/* FIXME: record a toc offset against a data-in-toc symbol */
-/* Now, there is currenly some confusion on what this means. In some 
-   compilers one sees the moral equivalent of:
-      .tocd
-      define some data
-      .text
-      refer to the data with a [tocv] qualifier
-   In general, one sees something to indicate that a tocd has been
-   seen, and that would trigger the allocation of data in toc. The IBM
-   docs seem to suggest that anything with the TOCDEFN qualifier should
-   never trigger storage allocation. However, in the kernel32.lib that 
-   we've been using for our test bed, there are a couple of variables
-   referenced that fail that test.
-
-   So it can't work that way.
-*/
-static int
-ppc_record_data_in_toc_entry(abfd, info, sec, sym, toc_kind)
-     bfd *abfd;
-     struct bfd_link_info *info;
-     asection *sec;
-     int sym;
-     enum toc_type toc_kind;
-{
-  bfd_byte *t;
-  bfd_byte *old_contents;
-  asection *s;
-  int element_size;
-  int data;
-  int offset;
-  struct ppc_coff_link_hash_entry *h = 0;
-  struct coff_symbol_struct *target;
-  int ret_val;
-  const char *name;
-
-  int *local_syms;
-
-  h = (struct ppc_coff_link_hash_entry *) (obj_coff_sym_hashes (abfd)[sym]);
-
-  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]);
+             (*_bfd_error_handler) (_("TOC overflow"));
+             bfd_set_error (bfd_error_file_too_big);
+             return false;
            }
        }
-
-      if (IS_UNALLOCATED(local_syms[sym])) 
-       {
-         local_syms[sym] = global_toc_size;
-         ret_val = global_toc_size;
-         global_toc_size += 4;
-#ifdef TOC_DEBUG
-         fprintf(stderr,
-                 "Setting data_in_toc_offset for local sym %d to %d\n",
-                 sym, ret_val);
-#endif
-       }
-      else
-       {
-         ret_val = local_syms[sym];
-#ifdef TOC_DEBUG
-         fprintf(stderr,
-                 "data_in_toc_offset already set for local sym %d to %d\n",
-                 sym, ret_val);
-#endif
-       }
-    }
-  else
-    {
-      CHECK_EYE(h->eye_catcher);
-
-      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))
-       {
-#if 0
-         h->toc_offset = global_toc_size;
-#endif
-         ret_val = global_toc_size;
-         /* We're allocating a chunk of the toc, as opposed to a slot */
-         /* FIXME: alignment? */
-         
-         global_toc_size += 4;
-#ifdef TOC_DEBUG
-         fprintf(stderr,
-                 "Setting data_in_toc_offset for sym %d (%s) [h=%p] to %d\n",
-                 sym, name, h, ret_val);
-#endif
-       }
-      else
-       {
-         ret_val = h->toc_offset;
-#ifdef TOC_DEBUG
-         fprintf(stderr,
-                 "data_in_toc_offset already set for sym %d (%s) [h=%p] to %d\n",
-                 sym, name, h, ret_val);
-#endif
-       }
     }
 
-  return ret_val;
+  return true;
 }
 
 /* record a toc offset against a symbol */
@@ -1089,7 +992,7 @@ ppc_mark_symbol_as_glue(abfd, sym, rel)
 
   h = (struct ppc_coff_link_hash_entry *) (obj_coff_sym_hashes (abfd)[sym]);
 
-  CHECK_EYE(h->eye_catcher);
+  HASH_CHECK(h);
 
   h->symbol_is_glue = 1;
   h->glue_insn = bfd_get_32 (abfd, (bfd_byte *) &rel->r_vaddr);
@@ -1097,29 +1000,8 @@ ppc_mark_symbol_as_glue(abfd, sym, rel)
   return;
 }
 
+#endif /* COFF_IMAGE_WITH_PE */
 \f
-/* Provided the symbol, returns the value reffed */
-static long get_symbol_value PARAMS ((asymbol *));
-
-static long
-get_symbol_value (symbol)       
-     asymbol *symbol;
-{                                             
-  long relocation = 0;
-
-  if (bfd_is_com_section (symbol->section))
-    {
-      relocation = 0;                           
-    }
-  else 
-    {                                      
-      relocation = symbol->value +
-       symbol->section->output_section->vma +
-         symbol->section->output_offset;
-    }                                           
-
-  return(relocation);
-}
 
 /* Return true if this relocation should
    appear in the output .reloc section. */
@@ -1130,10 +1012,21 @@ static boolean in_reloc_p(abfd, 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_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)  */
 /* FIXME: (it is not yet enabled) */
@@ -1154,17 +1047,10 @@ 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);
        
-  fprintf(stderr, "pe_ppc_reloc (%s)\n", TARGET_LITTLE_NAME);
-
   r_type = reloc_entry->howto->type;
 
   if (output_bfd) 
@@ -1189,7 +1075,7 @@ pe_ppc_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd,
   if ((part1_consth_active) && (r_type != IMAGE_REL_PPC_PAIR)) 
     {
       part1_consth_active = false;
-      *error_message = (char *) "Missing PAIR";
+      *error_message = (char *) _("Missing PAIR");
       return(bfd_reloc_dangerous);
     }
 
@@ -1199,6 +1085,8 @@ pe_ppc_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd,
   return(bfd_reloc_ok);        
 }
 
+#endif /* 0 */
+
 /* The reloc processing routine for the optimized COFF linker.  */
 
 static boolean
@@ -1221,14 +1109,6 @@ coff_ppc_relocate_section (output_bfd, info, input_bfd, input_section,
   bfd_vma relocation;
   reloc_howto_type *howto = 0;
   
-#ifdef DEBUG_RELOC
-  fprintf(stderr, 
-         "pe_ppc_relocate_section (%s) for %s \n", 
-         TARGET_LITTLE_NAME,
-         input_section->name);
-  
-#endif  
-
   /* 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.  */
@@ -1253,25 +1133,7 @@ coff_ppc_relocate_section (output_bfd, info, input_bfd, input_section,
 
       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);
   
-#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
-
       symndx = rel->r_symndx;
       loc = contents + rel->r_vaddr - input_section->vma;
 
@@ -1289,12 +1151,18 @@ coff_ppc_relocate_section (output_bfd, info, input_bfd, input_section,
            (obj_coff_sym_hashes (input_bfd)[symndx]);
          if (h != 0) 
            {
-             CHECK_EYE(h->eye_catcher);
+             HASH_CHECK(h);
            }
 
          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;
 
@@ -1308,13 +1176,14 @@ coff_ppc_relocate_section (output_bfd, info, input_bfd, input_section,
              sec = sections[symndx];
              val = (sec->output_section->vma
                     + sec->output_offset
-                    + sym->n_value
-                    - sec->vma);
+                    + sym->n_value);
+             if (! obj_pe (output_bfd))
+               val -= sec->vma;
            }
        }
       else
        {
-         CHECK_EYE(h->eye_catcher);
+         HASH_CHECK(h);
 
          if (h->root.root.type == bfd_link_hash_defined
              || h->root.root.type == bfd_link_hash_defweak)
@@ -1339,11 +1208,10 @@ coff_ppc_relocate_section (output_bfd, info, input_bfd, input_section,
       switch (r_type)
        {
        default:
-         fprintf( stderr, 
-                 "ERROR: during reloc processing -- unsupported reloc %s\n", 
-                 howto->name);
+         (*_bfd_error_handler)
+           (_("%s: unsupported relocation type 0x%02x"),
+            bfd_get_filename (input_bfd), r_type);
          bfd_set_error (bfd_error_bad_value);
-         abort();
          return false;
        case IMAGE_REL_PPC_TOCREL16:
          {
@@ -1356,16 +1224,10 @@ coff_ppc_relocate_section (output_bfd, info, input_bfd, input_section,
              {
                toc_section = bfd_get_section_by_name (bfd_of_toc_owner, 
                                                       TOC_SECTION_NAME);
-#ifdef TOC_DEBUG
-
-               fprintf(stderr,
-                       "BFD of toc owner %p, section addr of %s %p\n",
-                        bfd_of_toc_owner, TOC_SECTION_NAME, toc_section);
-#endif
 
                if ( toc_section == NULL ) 
                  {
-                   fprintf(stderr, "No Toc section!\n");
+                   /* There is no toc section. Something is very wrong. */
                    abort();
                  }
              }
@@ -1396,27 +1258,14 @@ coff_ppc_relocate_section (output_bfd, info, input_bfd, input_section,
                       again.
                     */
                    MAKE_ADDR_AGAIN(our_toc_offset);
-#ifdef TOC_DEBUG
-
-                   fprintf(stderr,
-                           "Not writing out toc_offset of %d for %s\n", 
-                           our_toc_offset, name);
-#endif
                  }
                else
                  {
                    /* write out the toc entry */
-                   record_toc(toc_section, our_toc_offset, priv, strdup(name));
-#ifdef TOC_DEBUG
-                   fprintf(stderr,
-                           "Writing out toc_offset "
-                           "toc_section (%p,%p)+%d val %d for %s\n", 
-                           toc_section,
-                           toc_section->contents,
-                           our_toc_offset, 
-                           val,
-                           name);
-#endif
+                   record_toc(toc_section, 
+                              our_toc_offset, 
+                              priv, 
+                              strdup(name));
 
                    bfd_put_32(output_bfd,
                               val,
@@ -1432,8 +1281,7 @@ coff_ppc_relocate_section (output_bfd, info, input_bfd, input_section,
                our_toc_offset = h->toc_offset;
 
                if ((r_flags & IMAGE_REL_PPC_TOCDEFN) 
-                   == IMAGE_REL_PPC_TOCDEFN 
-                   && IS_UNALLOCATED(our_toc_offset))
+                   == IMAGE_REL_PPC_TOCDEFN )
                  {
                    /* This is unbelievable cheese. Some knowledgable asm 
                       hacker has decided to use r2 as a base for loading 
@@ -1449,6 +1297,7 @@ coff_ppc_relocate_section (output_bfd, info, input_bfd, input_section,
                       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);
@@ -1456,10 +1305,11 @@ coff_ppc_relocate_section (output_bfd, info, input_bfd, input_section,
                    /* The size must still fit in a 16bit displacment */
                    if (our_toc_offset >= 65535)
                      {
-                       fprintf(stderr,
-                               "TOCDEFN Relocation exceeded "
-                               "displacment of 65535\n");
-                       abort();
+                       (*_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));
@@ -1471,28 +1321,11 @@ coff_ppc_relocate_section (output_bfd, info, input_bfd, input_section,
                       again.
                     */
                    MAKE_ADDR_AGAIN(our_toc_offset);
-#ifdef TOC_DEBUG
-                   fprintf(stderr,
-                           "Not writing out toc_offset of %d for %s\n", 
-                           our_toc_offset, name);
-#endif
                  }
                else
                  {
                    record_toc(toc_section, our_toc_offset, pub, strdup(name));
 
-#ifdef TOC_DEBUG
-                   /* write out the toc entry */
-                   fprintf(stderr,
-                           "Writing out toc_offset "
-                           "toc_section (%p,%p)+%d val %d for %s\n", 
-                           toc_section,
-                           toc_section->contents,
-                           our_toc_offset, 
-                           val,
-                           name);
-#endif
-
                    /* write out the toc entry */
                    bfd_put_32(output_bfd,
                               val,
@@ -1517,11 +1350,9 @@ coff_ppc_relocate_section (output_bfd, info, input_bfd, input_section,
                bfd_vma addr =  toc_section->output_section->vma
                  + toc_section->output_offset + our_toc_offset;
                    
-               fprintf(stderr,
-                       "  Toc Section reloc candidate\n");
-                   
                if (coff_data(output_bfd)->pe)
                  addr -= pe_data(output_bfd)->pe_opthdr.ImageBase;
+
                fwrite (&addr, 1,4, (FILE *) info->base_file);
              }
 
@@ -1530,9 +1361,12 @@ coff_ppc_relocate_section (output_bfd, info, input_bfd, input_section,
            if ( (r_flags & IMAGE_REL_PPC_TOCDEFN) != IMAGE_REL_PPC_TOCDEFN &&
                our_toc_offset > toc_section->_raw_size)
              {
-               fprintf(stderr,
-                       "reloc offset is bigger than the toc size!\n");
-               abort();
+               (*_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 */
@@ -1587,13 +1421,14 @@ coff_ppc_relocate_section (output_bfd, info, input_bfd, input_section,
              }
 
            fprintf(stderr, 
-                   "Warning: unsupported reloc %s <file %s, section %s>\n"
+                   _("Warning: unsupported reloc %s <file %s, section %s>\n")
                    howto->name,
                    bfd_get_filename(input_bfd),
                    input_section->name);
 
-           fprintf(stderr,"sym %d (%s), r_vaddr %d (%x)\n", 
-                   rel->r_symndx, my_name, rel->r_vaddr, rel->r_vaddr);  
+           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:
@@ -1604,21 +1439,45 @@ coff_ppc_relocate_section (output_bfd, info, input_bfd, input_section,
            if (h->symbol_is_glue == 1) 
              break;
            my_name = h->root.root.root.string;
-           fprintf(stderr, 
-                   "Warning: previously missed IMGLUE reloc %s <file %s, section %s>\n", 
-                   howto->name,
-                   bfd_get_filename(input_bfd),
-                   input_section->name);
-           break;
 
+           (*_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;
          }
-         break;
 
        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;
@@ -1645,8 +1504,7 @@ coff_ppc_relocate_section (output_bfd, info, input_bfd, input_section,
                                                 false, false, true);
                    if (myh == 0) 
                      {
-                       fprintf(stderr, "Missing idata magic cookies, "
-                               "this cannot work anyway...\n");
+                       /* Missing magic cookies. Something is very wrong. */
                        abort();
                      }
                    
@@ -1723,11 +1581,7 @@ coff_ppc_relocate_section (output_bfd, info, input_bfd, input_section,
              if (coff_data(output_bfd)->pe)
                {
                  addr -= pe_data(output_bfd)->pe_opthdr.ImageBase;
-                 fprintf(stderr,
-                         " adjusted down to %d", addr);
                }
-             fprintf(stderr, "\n");
-
              fwrite (&addr, 1,4, (FILE *) info->base_file);
            }
        }
@@ -1758,20 +1612,14 @@ coff_ppc_relocate_section (output_bfd, info, input_bfd, input_section,
                buf[SYMNMLEN] = '\0';
                name = buf;
              }
-#if 0
-           else
-             {
-               name = _bfd_coff_internal_syment_name (input_bfd, sym, buf);
-               if (name == NULL)
-                 return false;
-             }
-#endif
 
            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 false;
+             }
          }
        }
 
@@ -1782,7 +1630,11 @@ coff_ppc_relocate_section (output_bfd, info, input_bfd, input_section,
 
 #ifdef COFF_IMAGE_WITH_PE
 
-long int global_toc_size = 0;
+/* FIXME: BFD should not use global variables.  This file is compiled
+   twice, and these variables are shared.  This is confusing and
+   weird.  */
+
+long int global_toc_size = 4;
 
 bfd* bfd_of_toc_owner = 0;
 
@@ -1794,44 +1646,49 @@ struct list_ele *head;
 struct list_ele *tail;
 
 static char *
-h1 = "\n\t\t\tTOC MAPPING\n\n";
+h1 = N_("\n\t\t\tTOC MAPPING\n\n");
 static char *
-h2 = " TOC    disassembly  Comments       Name\n";
+h2 = N_(" TOC    disassembly  Comments       Name\n");
 static char *
-h3 = " Offset  spelling                   (if present)\n";
+h3 = N_(" Offset  spelling                   (if present)\n");
 
 void
-dump_toc(vfile)
-     void *vfile;
+dump_toc (vfile)
+     PTR vfile;
 {
-  FILE *file = vfile;
+  FILE *file = (FILE *) vfile;
   struct list_ele *t;
 
-  fprintf(file, h1);
-  fprintf(file, h2);
-  fprintf(file, h3);
+  fprintf(file, _(h1));
+  fprintf(file, _(h2));
+  fprintf(file, _(h3));
 
   for(t = head; t != 0; t=t->next)
     {
-      char *cat;
+      const char *cat = "";
 
       if (t->cat == priv)
-       cat = "private       ";
+       cat = _("private       ");
       else if (t->cat == pub)
-       cat = "public        ";
+       cat = _("public        ");
       else if (t->cat == data)
-       cat = "data-in-toc   ";
+       cat = _("data-in-toc   ");
 
       if (t->offset > global_toc_size)
        {
          if (t->offset <= global_toc_size + thunk_size)
-           cat = "IAT reference ";
+           cat = _("IAT reference ");
          else
-           cat = "Out of bounds!";
+           {
+             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)", t->offset, t->offset - 32768);
+             " %04lx    (%d)", (unsigned long) t->offset, t->offset - 32768);
       fprintf(file,
              "    %s %s\n",
              cat, t->name);
@@ -1854,19 +1711,18 @@ ppc_allocate_toc_section (info)
 
   if (bfd_of_toc_owner == 0)
     {
-      fprintf(stderr,
-             "There is no bfd that owns the toc section!\n");
+      /* No toc owner? Something is very wrong. */
       abort();
     }
 
   s = bfd_get_section_by_name ( bfd_of_toc_owner , TOC_SECTION_NAME);
   if (s == NULL) 
     {
-      fprintf(stderr, "No Toc section!\n");
+      /* No toc section? Something is very wrong. */
       abort();
     }
 
-  foo = bfd_alloc(bfd_of_toc_owner, global_toc_size);
+  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;
@@ -1883,12 +1739,6 @@ ppc_process_before_allocation (abfd, info)
   asection *sec;
   struct internal_reloc *i, *rel;
 
-#ifdef DEBUG_RELOC
-  fprintf(stderr, 
-         "ppc_process_before_allocation: BFD %s\n", 
-         bfd_get_filename(abfd));
-#endif
-
   /* 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. */
 
@@ -1904,15 +1754,6 @@ ppc_process_before_allocation (abfd, info)
 
   for (; sec != 0; sec = sec->next)
   {
-    int toc_offset;
-
-#ifdef DEBUG_RELOC
-    fprintf(stderr, 
-           "  section %s reloc count %d\n", 
-           sec->name, 
-           sec->reloc_count);
-#endif
-
     if (sec->reloc_count == 0) 
       continue;
 
@@ -1927,47 +1768,20 @@ ppc_process_before_allocation (abfd, info)
       {
        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);
+       boolean ok = true;
 
-#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
-       
        DUMP_RELOC2(ppc_coff_howto_table[r_type].name, rel);
 
        switch(r_type) 
          {
          case IMAGE_REL_PPC_TOCREL16:
-#if 0
-           /* FIXME:
-              This remains unimplemented for now, as it currently adds
-              un-necessary elements to the toc. All we need to do today
-              is not do anything if TOCDEFN is on.
-           */
-           if ( r_flags & IMAGE_REL_PPC_TOCDEFN )
-             toc_offset = ppc_record_data_in_toc_entry(abfd, info, sec, 
-                                                       rel->r_symndx, 
-                                                       default_toc);
-           else
-             toc_offset = ppc_record_toc_entry(abfd, info, sec, 
-                                               rel->r_symndx, default_toc);
-#endif
+           /* if TOCDEFN is on, ignore as someone else has allocated the
+              toc entry */
            if ( (r_flags & IMAGE_REL_PPC_TOCDEFN) != IMAGE_REL_PPC_TOCDEFN )
-             toc_offset = ppc_record_toc_entry(abfd, info, sec, 
-                                               rel->r_symndx, default_toc);
+             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);
@@ -1977,6 +1791,8 @@ ppc_process_before_allocation (abfd, info)
          }
       }
   }
+
+  return true;
 }
 
 #endif
@@ -2007,6 +1823,8 @@ ppc_refhi_reloc (abfd,
   return bfd_reloc_undefined;
 }
 
+#if 0
+
 static bfd_reloc_status_type
 ppc_reflo_reloc (abfd,
                 reloc_entry,
@@ -2032,6 +1850,8 @@ ppc_reflo_reloc (abfd,
   return bfd_reloc_undefined;
 }
 
+#endif
+
 static bfd_reloc_status_type
 ppc_pair_reloc (abfd,
                reloc_entry,
@@ -2085,6 +1905,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)           */
@@ -2113,6 +1935,8 @@ ppc_addr32nb_reloc (abfd,
   return bfd_reloc_ok;
 }
 
+#endif
+
 static bfd_reloc_status_type
 ppc_secrel_reloc (abfd,
                  reloc_entry,
@@ -2224,38 +2048,11 @@ ppc_coff_rtype2howto (relent, internal)
 
   /* 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) 
     {
@@ -2283,7 +2080,7 @@ ppc_coff_rtype2howto (relent, internal)
       break;
     default:
       fprintf(stderr, 
-             "Warning: Unsupported reloc %s [%d] used -- it may not work.\n",
+             _("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;      
@@ -2322,39 +2119,12 @@ 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:
@@ -2385,7 +2155,7 @@ coff_ppc_rtype_to_howto (abfd, sec, rel, h, sym, addendp)
       break;
     default:
       fprintf(stderr, 
-             "Warning: Unsupported reloc %s [%d] used -- it may not work.\n",
+             _("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;
@@ -2408,12 +2178,6 @@ 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);
@@ -2428,8 +2192,7 @@ ppc_coff_reloc_type_lookup (abfd, code)
     default: 
       return NULL;
     }
-  
-  return NULL;
+  /*NOTREACHED*/
 }
 
 #undef HOW2MAP
@@ -2440,8 +2203,7 @@ ppc_coff_reloc_type_lookup (abfd, code)
 #define RTYPE2HOWTO(cache_ptr, dst)  ppc_coff_rtype2howto (cache_ptr, dst)
 
 #ifndef COFF_IMAGE_WITH_PE
-static void
-ppc_coff_swap_sym_in_hook ();
+static void ppc_coff_swap_sym_in_hook PARAMS ((bfd *, PTR, PTR));
 #endif
 
 /* We use the special COFF backend linker, with our own special touch.  */
@@ -2449,6 +2211,7 @@ ppc_coff_swap_sym_in_hook ();
 #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
@@ -2485,19 +2248,15 @@ ppc_coff_swap_sym_in_hook (abfd, ext1, in1)
      PTR ext1;
      PTR in1;
 {
-  SYMENT *ext = (SYMENT *)ext1;
   struct internal_syment      *in = (struct internal_syment *)in1;
 
-#if 0
   if (bfd_of_toc_owner != 0) /* we already have a toc, so go home */
     return;
-#endif
 
   if (strcmp(in->_n._n_name, ".toc") == 0)
     {
       flagword flags;
       register asection *s;
-      char *foo;
 
       s = bfd_get_section_by_name ( abfd , TOC_SECTION_NAME);
       if (s != NULL) 
@@ -2507,20 +2266,13 @@ ppc_coff_swap_sym_in_hook (abfd, ext1, in1)
 
       flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY ;
 
-#ifdef TOC_DEBUG
-      fprintf(stderr,
-             "ppc_coff_swap_sym_in_hook: about to create the %s section\n",
-             TOC_SECTION_NAME);
-#endif
-
       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))
        {
-         fprintf(stderr,
-                 "toc section allocation failed!\n");
+         /* FIXME: set appropriate bfd error */
          abort();
        }
 
@@ -2532,6 +2284,544 @@ ppc_coff_swap_sym_in_hook (abfd, ext1, in1)
 }
 #endif
 
+#ifndef COFF_IMAGE_WITH_PE
+
+static boolean ppc_do_last PARAMS ((bfd *));
+static bfd *ppc_get_last PARAMS ((void));
+
+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
+  {
+    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. */
@@ -2542,14 +2832,20 @@ 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 */
@@ -2589,14 +2885,20 @@ 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 */
This page took 0.045408 seconds and 4 git commands to generate.