import gdb-2000-01-17 snapshot
[external/binutils.git] / bfd / coff-rs6000.c
index 31c51d5..6923000 100644 (file)
@@ -1,5 +1,6 @@
 /* BFD back-end for IBM RS/6000 "XCOFF" files.
-   Copyright 1990, 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+   Copyright 1990, 91, 92, 93, 94, 95, 96, 97, 98, 1999
+   Free Software Foundation, Inc.
    FIXME: Can someone provide a transliteration of this name into ASCII?
    Using the following chars caused a compiler warning on HIUX (so I replaced
    them with octal escapes), and isn't useful without an understanding of what
@@ -31,11 +32,19 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #include "bfd.h"
 #include "sysdep.h"
 #include "libbfd.h"
-#include "obstack.h"
 #include "coff/internal.h"
 #include "coff/rs6000.h"
 #include "libcoff.h"
 
+/* The main body of code is in coffcode.h.  */
+
+static boolean xcoff_mkobject PARAMS ((bfd *));
+static boolean xcoff_copy_private_bfd_data PARAMS ((bfd *, bfd *));
+static boolean xcoff_is_local_label_name PARAMS ((bfd *, const char *));
+static void xcoff_rtype2howto
+  PARAMS ((arelent *, struct internal_reloc *));
+static reloc_howto_type *xcoff_reloc_type_lookup
+  PARAMS ((bfd *, bfd_reloc_code_real_type));
 static boolean xcoff_slurp_armap PARAMS ((bfd *));
 static const bfd_target *xcoff_archive_p PARAMS ((bfd *));
 static PTR xcoff_read_ar_hdr PARAMS ((bfd *));
@@ -45,18 +54,105 @@ static const char *normalize_filename PARAMS ((bfd *));
 static boolean xcoff_write_armap
   PARAMS ((bfd *, unsigned int, struct orl *, unsigned int, int));
 static boolean xcoff_write_archive_contents PARAMS ((bfd *));
+static int _bfd_xcoff_sizeof_headers PARAMS ((bfd *, boolean));
+\f
+/* We use our own tdata type.  Its first field is the COFF tdata type,
+   so the COFF routines are compatible.  */
 
-/* The main body of code is in coffcode.h.  */
+static boolean
+xcoff_mkobject (abfd)
+     bfd *abfd;
+{
+  coff_data_type *coff;
 
-#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (3)
+  abfd->tdata.xcoff_obj_data =
+    ((struct xcoff_tdata *)
+     bfd_zalloc (abfd, sizeof (struct xcoff_tdata)));
+  if (abfd->tdata.xcoff_obj_data == NULL)
+    return false;
+  coff = coff_data (abfd);
+  coff->symbols = (coff_symbol_type *) NULL;
+  coff->conversion_table = (unsigned int *) NULL;
+  coff->raw_syments = (struct coff_ptr_struct *) NULL;
+  coff->relocbase = 0;
+
+  xcoff_data (abfd)->modtype = ('1' << 8) | 'L';
+
+  /* We set cputype to -1 to indicate that it has not been
+     initialized.  */
+  xcoff_data (abfd)->cputype = -1;
+
+  xcoff_data (abfd)->csects = NULL;
+  xcoff_data (abfd)->debug_indices = NULL;
+
+  return true;
+}
+
+/* Copy XCOFF data from one BFD to another.  */
+
+static boolean
+xcoff_copy_private_bfd_data (ibfd, obfd)
+     bfd *ibfd;
+     bfd *obfd;
+{
+  struct xcoff_tdata *ix, *ox;
+  asection *sec;
+
+  if (ibfd->xvec != obfd->xvec)
+    return true;
+  ix = xcoff_data (ibfd);
+  ox = xcoff_data (obfd);
+  ox->full_aouthdr = ix->full_aouthdr;
+  ox->toc = ix->toc;
+  if (ix->sntoc == 0)
+    ox->sntoc = 0;
+  else
+    {
+      sec = coff_section_from_bfd_index (ibfd, ix->sntoc);
+      if (sec == NULL)
+       ox->sntoc = 0;
+      else
+       ox->sntoc = sec->output_section->target_index;
+    }
+  if (ix->snentry == 0)
+    ox->snentry = 0;
+  else
+    {
+      sec = coff_section_from_bfd_index (ibfd, ix->snentry);
+      if (sec == NULL)
+       ox->snentry = 0;
+      else
+       ox->snentry = sec->output_section->target_index;
+    }
+  ox->text_align_power = ix->text_align_power;
+  ox->data_align_power = ix->data_align_power;
+  ox->modtype = ix->modtype;
+  ox->cputype = ix->cputype;
+  ox->maxdata = ix->maxdata;
+  ox->maxstack = ix->maxstack;
+  return true;
+}
+
+/* I don't think XCOFF really has a notion of local labels based on
+   name.  This will mean that ld -X doesn't actually strip anything.
+   The AIX native linker does not have a -X option, and it ignores the
+   -x option.  */
 
+static boolean
+xcoff_is_local_label_name (abfd, name)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     const char *name ATTRIBUTE_UNUSED;
+{
+  return false;
+}
+\f
 /* The XCOFF reloc table.  Actually, XCOFF relocations specify the
    bitsize and whether they are signed or not, along with a
    conventional type.  This table is for the types, which are used for
    different algorithms for putting in the reloc.  Many of these
    relocs need special_function entries, which I have not written.  */
 
-static reloc_howto_type rs6000coff_howto_table[] =
+static reloc_howto_type xcoff_howto_table[] =
 {
   /* Standard 32 bit relocation.  */
   HOWTO (0,                    /* type */                                 
@@ -110,7 +206,7 @@ static reloc_howto_type rs6000coff_howto_table[] =
         16,                    /* bitsize */                   
         false,                 /* pc_relative */                          
         0,                     /* bitpos */                               
-        complain_overflow_signed, /* complain_on_overflow */
+        complain_overflow_bitfield, /* complain_on_overflow */
         0,                     /* special_function */                     
         "R_TOC",               /* name */                                 
         true,                  /* partial_inplace */                      
@@ -163,7 +259,7 @@ static reloc_howto_type rs6000coff_howto_table[] =
         0xffff,                /* dst_mask */                             
         false),                /* pcrel_offset */
   
-  { 7 },
+  EMPTY_HOWTO (7),
   
   /* Non modifiable absolute branch.  */
   HOWTO (8,                    /* type */                                 
@@ -180,7 +276,7 @@ static reloc_howto_type rs6000coff_howto_table[] =
         0x3fffffc,             /* dst_mask */                             
         false),                /* pcrel_offset */
   
-  { 9 },
+  EMPTY_HOWTO (9),
 
   /* Non modifiable relative branch.  */
   HOWTO (0xa,                  /* type */                                 
@@ -197,7 +293,7 @@ static reloc_howto_type rs6000coff_howto_table[] =
         0x3fffffc,             /* dst_mask */                             
         false),                /* pcrel_offset */
   
-  { 0xb },
+  EMPTY_HOWTO (0xb),
 
   /* Indirect load.  */
   HOWTO (0xc,                  /* type */                                 
@@ -229,7 +325,7 @@ static reloc_howto_type rs6000coff_howto_table[] =
         0xffff,                /* dst_mask */                             
         false),                /* pcrel_offset */
   
-  { 0xe },
+  EMPTY_HOWTO (0xe),
   
   /* Non-relocating reference.  */
   HOWTO (0xf,                  /* type */                                 
@@ -246,8 +342,8 @@ static reloc_howto_type rs6000coff_howto_table[] =
         0,                     /* dst_mask */                             
         false),                /* pcrel_offset */
   
-  { 0x10 },
-  { 0x11 },
+  EMPTY_HOWTO (0x10),
+  EMPTY_HOWTO (0x11),
   
   /* TOC relative indirect load.  */
   HOWTO (0x12,                 /* type */                                 
@@ -333,7 +429,7 @@ static reloc_howto_type rs6000coff_howto_table[] =
         0,                     /* bitpos */                               
         complain_overflow_bitfield, /* complain_on_overflow */
         0,                     /* special_function */                     
-        "R_REL",               /* name */                                 
+        "R_CREL",              /* name */                                 
         true,                  /* partial_inplace */                      
         0xffff,                /* src_mask */                             
         0xffff,                /* dst_mask */                             
@@ -378,7 +474,7 @@ static reloc_howto_type rs6000coff_howto_table[] =
         0,                     /* bitpos */                               
         complain_overflow_signed, /* complain_on_overflow */
         0,                     /* special_function */                     
-        "R_REL",               /* name */                                 
+        "R_RBR",               /* name */                                 
         true,                  /* partial_inplace */                      
         0xffff,                /* src_mask */                             
         0xffff,                /* dst_mask */                             
@@ -393,24 +489,19 @@ static reloc_howto_type rs6000coff_howto_table[] =
         0,                     /* bitpos */                               
         complain_overflow_bitfield, /* complain_on_overflow */
         0,                     /* special_function */                     
-        "R_REL",               /* name */                                 
+        "R_RBRC",              /* name */                                 
         true,                  /* partial_inplace */                      
         0xffff,                /* src_mask */                             
         0xffff,                /* dst_mask */                             
         false)                 /* pcrel_offset */
 };
 
-#define RTYPE2HOWTO(cache_ptr, dst) rs6000coff_rtype2howto (cache_ptr, dst)
-
-static void rs6000coff_rtype2howto PARAMS ((arelent *,
-                                           struct internal_reloc *));
-
 static void
-rs6000coff_rtype2howto (relent, internal)
+xcoff_rtype2howto (relent, internal)
      arelent *relent;
      struct internal_reloc *internal;
 {
-  relent->howto = rs6000coff_howto_table + internal->r_type;
+  relent->howto = xcoff_howto_table + internal->r_type;
 
   /* The r_size field of an XCOFF reloc encodes the bitsize of the
      relocation, as well as indicating whether it is signed or not.
@@ -426,26 +517,22 @@ rs6000coff_rtype2howto (relent, internal)
 #endif
 }
 
-#define coff_bfd_reloc_type_lookup rs6000coff_reloc_type_lookup
-
-static reloc_howto_type *rs6000coff_reloc_type_lookup
-  PARAMS ((bfd *, bfd_reloc_code_real_type));
-
 static reloc_howto_type *
-rs6000coff_reloc_type_lookup (abfd, code)
-     bfd *abfd;
+xcoff_reloc_type_lookup (abfd, code)
+     bfd *abfd ATTRIBUTE_UNUSED;
      bfd_reloc_code_real_type code;
 {
   switch (code)
     {
     case BFD_RELOC_PPC_B26:
-      return &rs6000coff_howto_table[0xa];
+      return &xcoff_howto_table[0xa];
     case BFD_RELOC_PPC_BA26:
-      return &rs6000coff_howto_table[8];
+      return &xcoff_howto_table[8];
     case BFD_RELOC_PPC_TOC16:
-      return &rs6000coff_howto_table[3];
+      return &xcoff_howto_table[3];
     case BFD_RELOC_32:
-      return &rs6000coff_howto_table[0];
+    case BFD_RELOC_CTOR:
+      return &xcoff_howto_table[0];
     default:
       return NULL;
     }
@@ -460,9 +547,19 @@ rs6000coff_reloc_type_lookup (abfd, code)
        : 0)                                                            \
        | (howto->bitsize - 1));                                                \
   }
+\f
+#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (3)
 
 #define COFF_LONG_FILENAMES
 
+#define RTYPE2HOWTO(cache_ptr, dst) xcoff_rtype2howto (cache_ptr, dst)
+
+#define coff_mkobject xcoff_mkobject
+#define coff_bfd_copy_private_bfd_data xcoff_copy_private_bfd_data
+#define coff_bfd_is_local_label_name xcoff_is_local_label_name
+#define coff_bfd_reloc_type_lookup xcoff_reloc_type_lookup
+#define coff_relocate_section _bfd_ppc_xcoff_relocate_section
+
 #include "coffcode.h"
 \f
 /* XCOFF archive support.  The original version of this code was by
@@ -590,6 +687,10 @@ struct xcoff_ar_hdr
    bfd_false)
 #define xcoff_truncate_arname bfd_dont_truncate_arname
 
+/* We can use the standard get_elt_at_index routine.  */
+
+#define xcoff_get_elt_at_index _bfd_generic_get_elt_at_index
+
 /* XCOFF archives do not have a timestamp.  */
 
 #define xcoff_update_armap_timestamp bfd_true
@@ -638,10 +739,7 @@ xcoff_slurp_armap (abfd)
   sz = strtol (hdr.size, (char **) NULL, 10);
   contents = (bfd_byte *) bfd_alloc (abfd, sz);
   if (contents == NULL)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      return false;
-    }
+    return false;
   if (bfd_read ((PTR) contents, 1, sz, abfd) != sz)
     return false;
 
@@ -657,10 +755,7 @@ xcoff_slurp_armap (abfd)
   bfd_ardata (abfd)->symdefs = ((carsym *)
                                bfd_alloc (abfd, c * sizeof (carsym)));
   if (bfd_ardata (abfd)->symdefs == NULL)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      return false;
-    }
+    return false;
 
   /* After the count comes a list of four byte file offsets.  */
   for (i = 0, arsym = bfd_ardata (abfd)->symdefs, p = contents + 4;
@@ -717,10 +812,7 @@ xcoff_archive_p (abfd)
     (struct artdata *) bfd_zalloc (abfd, sizeof (struct artdata));
 
   if (bfd_ardata (abfd) == (struct artdata *) NULL)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      return NULL;
-    }
+    return NULL;
 
   bfd_ardata (abfd)->first_file_filepos = strtol (hdr.firstmemoff,
                                                  (char **) NULL, 10);
@@ -731,10 +823,7 @@ xcoff_archive_p (abfd)
 
   bfd_ardata (abfd)->tdata = bfd_zalloc (abfd, SIZEOF_AR_FILE_HDR);
   if (bfd_ardata (abfd)->tdata == NULL)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      return NULL;
-    }
+    return NULL;
 
   memcpy (bfd_ardata (abfd)->tdata, &hdr, SIZEOF_AR_FILE_HDR);
 
@@ -763,12 +852,9 @@ xcoff_read_ar_hdr (abfd)
     return NULL;
 
   namlen = strtol (hdr.namlen, (char **) NULL, 10);
-  hdrp = bfd_alloc (abfd, SIZEOF_AR_HDR + namlen + 1);
+  hdrp = (struct xcoff_ar_hdr *) bfd_alloc (abfd, SIZEOF_AR_HDR + namlen + 1);
   if (hdrp == NULL)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      return NULL;
-    }
+    return NULL;
   memcpy (hdrp, &hdr, SIZEOF_AR_HDR);
   if (bfd_read ((char *) hdrp + SIZEOF_AR_HDR, 1, namlen, abfd) != namlen)
     return NULL;
@@ -776,10 +862,7 @@ xcoff_read_ar_hdr (abfd)
 
   ret = (struct areltdata *) bfd_alloc (abfd, sizeof (struct areltdata));
   if (ret == NULL)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      return NULL;
-    }
+    return NULL;
   ret->arch_header = (char *) hdrp;
   ret->parsed_size = strtol (hdr.size, (char **) NULL, 10);
   ret->filename = (char *) hdrp + SIZEOF_AR_HDR;
@@ -826,7 +909,7 @@ xcoff_openr_next_archived_file (archive, last_file)
 
 /* Stat an element in an XCOFF archive.  */
 
-int
+static int
 xcoff_generic_stat_arch_elt (abfd, s)
      bfd *abfd;
      struct stat *s;
@@ -874,14 +957,14 @@ normalize_filename (abfd)
 static boolean
 xcoff_write_armap (abfd, elength, map, orl_count, stridx)
      bfd *abfd;
-     unsigned int elength;
+     unsigned int elength ATTRIBUTE_UNUSED;
      struct orl *map;
      unsigned int orl_count;
      int stridx;
 {
   struct xcoff_ar_hdr hdr;
   char *p;
-  char buf[4];
+  unsigned char buf[4];
   bfd *sub;
   file_ptr fileoff;
   unsigned int i;
@@ -991,10 +1074,7 @@ xcoff_write_archive_contents (abfd)
     }
   offsets = (file_ptr *) bfd_alloc (abfd, count * sizeof (file_ptr));
   if (offsets == NULL)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      return false;
-    }
+    return false;
 
   if (bfd_seek (abfd, SIZEOF_AR_FILE_HDR, SEEK_SET) != 0)
     return false;
@@ -1033,7 +1113,7 @@ xcoff_write_archive_contents (abfd)
          if (stat (bfd_get_filename (sub), &s) != 0)
            {
              bfd_set_error (bfd_error_system_call);
-             return NULL;
+             return false;
            }
 
          sprintf (ahdrp->size, "%ld", (long) s.st_size);
@@ -1044,13 +1124,9 @@ xcoff_write_archive_contents (abfd)
 
          if (sub->arelt_data == NULL)
            {
-             sub->arelt_data = ((struct areltdata *)
-                                bfd_alloc (sub, sizeof (struct areltdata)));
+             sub->arelt_data = bfd_alloc (sub, sizeof (struct areltdata));
              if (sub->arelt_data == NULL)
-               {
-                 bfd_set_error (bfd_error_no_memory);
-                 return false;
-               }
+               return false;
            }
 
          arch_eltdata (sub)->parsed_size = s.st_size;
@@ -1211,6 +1287,26 @@ xcoff_write_archive_contents (abfd)
   return true;
 }
 \f
+/* We can't use the usual coff_sizeof_headers routine, because AIX
+   always uses an a.out header.  */
+
+/*ARGSUSED*/
+static int
+_bfd_xcoff_sizeof_headers (abfd, reloc)
+     bfd *abfd;
+     boolean reloc ATTRIBUTE_UNUSED;
+{
+  int size;
+
+  size = FILHSZ;
+  if (xcoff_data (abfd)->full_aouthdr)
+    size += AOUTSZ;
+  else
+    size += SMALL_AOUTSZ;
+  size += abfd->section_count * SCNHSZ;
+  return size;
+}
+\f
 #define CORE_FILE_P _bfd_dummy_target
 
 #define coff_core_file_failing_command _bfd_nocore_core_file_failing_command
@@ -1262,17 +1358,32 @@ extern int lynx_core_file_failing_signal PARAMS ((bfd *abfd));
 
 #endif /* LYNX_CORE */
 
+#define _bfd_xcoff_bfd_get_relocated_section_contents \
+  coff_bfd_get_relocated_section_contents
+#define _bfd_xcoff_bfd_relax_section coff_bfd_relax_section
+#define _bfd_xcoff_bfd_gc_sections coff_bfd_gc_sections
+#define _bfd_xcoff_bfd_link_split_section coff_bfd_link_split_section
+
 /* The transfer vector that leads the outside world to all of the above. */
 
-const bfd_target rs6000coff_vec =
+const bfd_target
+#ifdef TARGET_SYM
+  TARGET_SYM =
+#else
+  rs6000coff_vec =
+#endif
 {
+#ifdef TARGET_NAME
+  TARGET_NAME,
+#else
   "aixcoff-rs6000",            /* name */
+#endif
   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 |                /* object flags */
-   HAS_LINENO | HAS_DEBUG |
+   HAS_LINENO | HAS_DEBUG | DYNAMIC |
    HAS_SYMS | HAS_LOCALS | WP_TEXT),
 
   (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
@@ -1301,8 +1412,10 @@ const bfd_target rs6000coff_vec =
      BFD_JUMP_TABLE_SYMBOLS (coff),
      BFD_JUMP_TABLE_RELOCS (coff),
      BFD_JUMP_TABLE_WRITE (coff),
-     BFD_JUMP_TABLE_LINK (coff),
-     BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
+     BFD_JUMP_TABLE_LINK (_bfd_xcoff),
+     BFD_JUMP_TABLE_DYNAMIC (_bfd_xcoff),
 
-  COFF_SWAP_TABLE,
+  NULL,
+  
+  COFF_SWAP_TABLE
 };