* elf.c (bfd_elf_print_symbol): Print the st_other field if it is
[deliverable/binutils-gdb.git] / bfd / xcofflink.c
index acf134d9764e6ff5bcc87c15b713e4a5cefb7285..3892f171516d52c7e213a1ff7542fba7481574d9 100644 (file)
@@ -256,7 +256,7 @@ struct xcoff_link_hash_entry
         set), this is the offset in toc_section.  */
       bfd_vma toc_offset;
       /* If the TOC entry comes from an input file, this is set to the
-         symbo lindex of the C_HIDEXT XMC_TC symbol.  */
+         symbol index of the C_HIDEXT XMC_TC or XMC_TD symbol.  */
       long toc_indx;
     } u;
 
@@ -300,6 +300,8 @@ struct xcoff_link_hash_entry
 #define XCOFF_HAS_SIZE (04000)
   /* Symbol is a function descriptor.  */
 #define XCOFF_DESCRIPTOR (010000)
+  /* Multiple definitions have been for the symbol.  */
+#define XCOFF_MULTIPLY_DEFINED (020000)
 
   /* The storage mapping class.  */
   unsigned char smclas;
@@ -435,6 +437,8 @@ static void xcoff_swap_ldsym_in
   PARAMS ((bfd *, const struct external_ldsym *, struct internal_ldsym *));
 static void xcoff_swap_ldsym_out
   PARAMS ((bfd *, const struct internal_ldsym *, struct external_ldsym *));
+static void xcoff_swap_ldrel_in
+  PARAMS ((bfd *, const struct external_ldrel *, struct internal_ldrel *));
 static void xcoff_swap_ldrel_out
   PARAMS ((bfd *, const struct internal_ldrel *, struct external_ldrel *));
 static struct bfd_hash_entry *xcoff_link_hash_newfunc
@@ -448,6 +452,8 @@ static boolean xcoff_link_check_archive_element
   PARAMS ((bfd *, struct bfd_link_info *, boolean *));
 static boolean xcoff_link_check_ar_symbols
   PARAMS ((bfd *, struct bfd_link_info *, boolean *));
+static boolean xcoff_link_check_dynamic_ar_symbols
+  PARAMS ((bfd *, struct bfd_link_info *, boolean *));
 static bfd_size_type xcoff_find_reloc
   PARAMS ((struct internal_reloc *, bfd_size_type, bfd_vma));
 static boolean xcoff_link_add_symbols PARAMS ((bfd *, struct bfd_link_info *));
@@ -553,7 +559,19 @@ xcoff_swap_ldsym_out (abfd, src, dst)
   bfd_put_32 (abfd, src->l_parm, dst->l_parm);
 }
 
-/* As it happens, we never need to swap in the ldrel structure.  */
+/* Swap in the ldrel structure.  */
+
+static void
+xcoff_swap_ldrel_in (abfd, src, dst)
+     bfd *abfd;
+     const struct external_ldrel *src;
+     struct internal_ldrel *dst;
+{
+  dst->l_vaddr = bfd_get_32 (abfd, src->l_vaddr);
+  dst->l_symndx = bfd_get_32 (abfd, src->l_symndx);
+  dst->l_rtype = bfd_get_16 (abfd, src->l_rtype);
+  dst->l_rsecnm = bfd_get_16 (abfd, src->l_rsecnm);
+}
 
 /* Swap out the ldrel structure.  */
 
@@ -569,6 +587,316 @@ xcoff_swap_ldrel_out (abfd, src, dst)
   bfd_put_16 (abfd, src->l_rsecnm, dst->l_rsecnm);
 }
 \f
+/* Routines to read XCOFF dynamic information.  This don't really
+   belong here, but we already have the ldsym manipulation routines
+   here.  */
+
+/* Read the contents of a section.  */
+
+static boolean
+xcoff_get_section_contents (abfd, sec)
+     bfd *abfd;
+     asection *sec;
+{
+  if (coff_section_data (abfd, sec) == NULL)
+    {
+      sec->used_by_bfd = bfd_zalloc (abfd,
+                                    sizeof (struct coff_section_tdata));
+      if (sec->used_by_bfd == NULL)
+       return false;
+    }
+
+  if (coff_section_data (abfd, sec)->contents == NULL)
+    {
+      coff_section_data (abfd, sec)->contents = bfd_malloc (sec->_raw_size);
+      if (coff_section_data (abfd, sec)->contents == NULL)
+       return false;
+
+      if (! bfd_get_section_contents (abfd, sec,
+                                     coff_section_data (abfd, sec)->contents,
+                                     (file_ptr) 0, sec->_raw_size))
+       return false;
+    }
+
+  return true;
+}
+
+/* Get the size required to hold the dynamic symbols.  */
+
+long
+_bfd_xcoff_get_dynamic_symtab_upper_bound (abfd)
+     bfd *abfd;
+{
+  asection *lsec;
+  bfd_byte *contents;
+  struct internal_ldhdr ldhdr;
+
+  if ((abfd->flags & DYNAMIC) == 0)
+    {
+      bfd_set_error (bfd_error_invalid_operation);
+      return -1;
+    }
+
+  lsec = bfd_get_section_by_name (abfd, ".loader");
+  if (lsec == NULL)
+    {
+      bfd_set_error (bfd_error_no_symbols);
+      return -1;
+    }
+
+  if (! xcoff_get_section_contents (abfd, lsec))
+    return -1;
+  contents = coff_section_data (abfd, lsec)->contents;
+
+  xcoff_swap_ldhdr_in (abfd, (struct external_ldhdr *) contents, &ldhdr);
+
+  return (ldhdr.l_nsyms + 1) * sizeof (asymbol *);
+}
+
+/* Get the dynamic symbols.  */
+
+long
+_bfd_xcoff_canonicalize_dynamic_symtab (abfd, psyms)
+     bfd *abfd;
+     asymbol **psyms;
+{
+  asection *lsec;
+  bfd_byte *contents;
+  struct internal_ldhdr ldhdr;
+  const char *strings;
+  struct external_ldsym *elsym, *elsymend;
+  coff_symbol_type *symbuf;
+
+  if ((abfd->flags & DYNAMIC) == 0)
+    {
+      bfd_set_error (bfd_error_invalid_operation);
+      return -1;
+    }
+
+  lsec = bfd_get_section_by_name (abfd, ".loader");
+  if (lsec == NULL)
+    {
+      bfd_set_error (bfd_error_no_symbols);
+      return -1;
+    }
+
+  if (! xcoff_get_section_contents (abfd, lsec))
+    return -1;
+  contents = coff_section_data (abfd, lsec)->contents;
+
+  coff_section_data (abfd, lsec)->keep_contents = true;
+
+  xcoff_swap_ldhdr_in (abfd, (struct external_ldhdr *) contents, &ldhdr);
+
+  strings = (char *) contents + ldhdr.l_stoff;
+
+  symbuf = ((coff_symbol_type *)
+           bfd_zalloc (abfd, ldhdr.l_nsyms * sizeof (coff_symbol_type)));
+  if (symbuf == NULL)
+    return -1;
+
+  elsym = (struct external_ldsym *) (contents + LDHDRSZ);
+  elsymend = elsym + ldhdr.l_nsyms;
+  for (; elsym < elsymend; elsym++, symbuf++, psyms++)
+    {
+      struct internal_ldsym ldsym;
+
+      xcoff_swap_ldsym_in (abfd, elsym, &ldsym);
+
+      symbuf->symbol.the_bfd = abfd;
+
+      if (ldsym._l._l_l._l_zeroes == 0)
+       symbuf->symbol.name = strings + ldsym._l._l_l._l_offset;
+      else
+       {
+         int i;
+
+         for (i = 0; i < SYMNMLEN; i++)
+           if (ldsym._l._l_name[i] == '\0')
+             break;
+         if (i < SYMNMLEN)
+           symbuf->symbol.name = elsym->_l._l_name;
+         else
+           {
+             char *c;
+
+             c = bfd_alloc (abfd, SYMNMLEN + 1);
+             if (c == NULL)
+               return -1;
+             memcpy (c, ldsym._l._l_name, SYMNMLEN);
+             c[SYMNMLEN] = '\0';
+             symbuf->symbol.name = c;
+           }
+       }
+
+      if (ldsym.l_smclas == XMC_XO)
+       symbuf->symbol.section = bfd_abs_section_ptr;
+      else
+       symbuf->symbol.section = coff_section_from_bfd_index (abfd,
+                                                             ldsym.l_scnum);
+      symbuf->symbol.value = ldsym.l_value - symbuf->symbol.section->vma;
+
+      symbuf->symbol.flags = BSF_NO_FLAGS;
+      if ((ldsym.l_smtype & L_EXPORT) != 0)
+       symbuf->symbol.flags |= BSF_GLOBAL;
+
+      /* FIXME: We have no way to record the other information stored
+         with the loader symbol.  */
+
+      *psyms = (asymbol *) symbuf;
+    }
+
+  *psyms = NULL;
+
+  return ldhdr.l_nsyms;
+}
+
+/* Get the size required to hold the dynamic relocs.  */
+
+long
+_bfd_xcoff_get_dynamic_reloc_upper_bound (abfd)
+     bfd *abfd;
+{
+  asection *lsec;
+  bfd_byte *contents;
+  struct internal_ldhdr ldhdr;
+
+  if ((abfd->flags & DYNAMIC) == 0)
+    {
+      bfd_set_error (bfd_error_invalid_operation);
+      return -1;
+    }
+
+  lsec = bfd_get_section_by_name (abfd, ".loader");
+  if (lsec == NULL)
+    {
+      bfd_set_error (bfd_error_no_symbols);
+      return -1;
+    }
+
+  if (! xcoff_get_section_contents (abfd, lsec))
+    return -1;
+  contents = coff_section_data (abfd, lsec)->contents;
+
+  xcoff_swap_ldhdr_in (abfd, (struct external_ldhdr *) contents, &ldhdr);
+
+  return (ldhdr.l_nreloc + 1) * sizeof (arelent *);
+}
+
+/* The typical dynamic reloc.  */
+
+static reloc_howto_type xcoff_dynamic_reloc =
+  HOWTO (0,                    /* type */                                 
+        0,                     /* rightshift */                           
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */ 
+        32,                    /* bitsize */                   
+        false,                 /* pc_relative */                          
+        0,                     /* bitpos */                               
+        complain_overflow_bitfield, /* complain_on_overflow */
+        0,                     /* special_function */                     
+        "R_POS",               /* name */                                 
+        true,                  /* partial_inplace */                      
+        0xffffffff,            /* src_mask */                             
+        0xffffffff,            /* dst_mask */                             
+        false);                /* pcrel_offset */
+
+/* Get the dynamic relocs.  */
+
+long
+_bfd_xcoff_canonicalize_dynamic_reloc (abfd, prelocs, syms)
+     bfd *abfd;
+     arelent **prelocs;
+     asymbol **syms;
+{
+  asection *lsec;
+  bfd_byte *contents;
+  struct internal_ldhdr ldhdr;
+  arelent *relbuf;
+  struct external_ldrel *elrel, *elrelend;
+
+  if ((abfd->flags & DYNAMIC) == 0)
+    {
+      bfd_set_error (bfd_error_invalid_operation);
+      return -1;
+    }
+
+  lsec = bfd_get_section_by_name (abfd, ".loader");
+  if (lsec == NULL)
+    {
+      bfd_set_error (bfd_error_no_symbols);
+      return -1;
+    }
+
+  if (! xcoff_get_section_contents (abfd, lsec))
+    return -1;
+  contents = coff_section_data (abfd, lsec)->contents;
+
+  xcoff_swap_ldhdr_in (abfd, (struct external_ldhdr *) contents, &ldhdr);
+
+  relbuf = (arelent *) bfd_alloc (abfd, ldhdr.l_nreloc * sizeof (arelent));
+  if (relbuf == NULL)
+    return -1;
+
+  elrel = ((struct external_ldrel *)
+          (contents + LDHDRSZ + ldhdr.l_nsyms * LDSYMSZ));
+  elrelend = elrel + ldhdr.l_nreloc;
+  for (; elrel < elrelend; elrel++, relbuf++, prelocs++)
+    {
+      struct internal_ldrel ldrel;
+
+      xcoff_swap_ldrel_in (abfd, elrel, &ldrel);
+
+      if (ldrel.l_symndx >= 3)
+       relbuf->sym_ptr_ptr = syms + (ldrel.l_symndx - 3);
+      else
+       {
+         const char *name;
+         asection *sec;
+
+         switch (ldrel.l_symndx)
+           {
+           case 0:
+             name = ".text";
+             break;
+           case 1:
+             name = ".data";
+             break;
+           case 2:
+             name = ".bss";
+             break;
+           default:
+             abort ();
+             break;
+           }
+
+         sec = bfd_get_section_by_name (abfd, name);
+         if (sec == NULL)
+           {
+             bfd_set_error (bfd_error_bad_value);
+             return -1;
+           }
+
+         relbuf->sym_ptr_ptr = sec->symbol_ptr_ptr;
+       }
+
+      relbuf->address = ldrel.l_vaddr;
+      relbuf->addend = 0;
+
+      /* Most dynamic relocs have the same type.  FIXME: This is only
+         correct if ldrel.l_rtype == 0.  In other cases, we should use
+         a different howto.  */
+      relbuf->howto = &xcoff_dynamic_reloc;
+
+      /* FIXME: We have no way to record the l_rsecnm field.  */
+
+      *prelocs = relbuf;
+    }
+
+  *prelocs = NULL;
+
+  return ldhdr.l_nreloc;
+}
+\f
 /* Routine to create an entry in an XCOFF link hash table.  */
 
 static struct bfd_hash_entry *
@@ -735,9 +1063,45 @@ _bfd_xcoff_bfd_link_add_symbols (abfd, info)
     {
     case bfd_object:
       return xcoff_link_add_object_symbols (abfd, info);
+
     case bfd_archive:
-      return (_bfd_generic_link_add_archive_symbols
-             (abfd, info, xcoff_link_check_archive_element));
+      /* If the archive has a map, do the usual search.  We then need
+         to check the archive for stripped dynamic objects, because
+         they will not appear in the archive map even though they
+         should, perhaps, be included.  If the archive has no map, we
+         just consider each object file in turn, since that apparently
+         is what the AIX native linker does.  */
+      if (bfd_has_map (abfd))
+       {
+         if (! (_bfd_generic_link_add_archive_symbols
+                (abfd, info, xcoff_link_check_archive_element)))
+           return false;
+       }
+
+      {
+       bfd *member;
+
+       member = bfd_openr_next_archived_file (abfd, (bfd *) NULL);
+       while (member != NULL)
+         {
+           if (bfd_check_format (member, bfd_object)
+               && (! bfd_has_map (abfd)
+                   || ((member->flags & DYNAMIC) != 0
+                       && (member->flags & HAS_SYMS) == 0)))
+             {
+               boolean needed;
+
+               if (! xcoff_link_check_archive_element (member, info, &needed))
+                 return false;
+               if (needed)
+                 member->archive_pass = -1;
+             }
+           member = bfd_openr_next_archived_file (abfd, member);
+         }
+      }
+
+      return true;
+
     default:
       bfd_set_error (bfd_error_wrong_format);
       return false;
@@ -810,6 +1174,11 @@ xcoff_link_check_ar_symbols (abfd, info, pneeded)
 
   *pneeded = false;
 
+  if ((abfd->flags & DYNAMIC) != 0
+      && ! info->static_link
+      && info->hash->creator == abfd->xvec)
+    return xcoff_link_check_dynamic_ar_symbols (abfd, info, pneeded);
+
   symesz = bfd_coff_symesz (abfd);
   esym = (bfd_byte *) obj_coff_external_syms (abfd);
   esym_end = esym + obj_raw_syment_count (abfd) * symesz;
@@ -839,7 +1208,10 @@ xcoff_link_check_ar_symbols (abfd, info, pneeded)
             defines it.  We also don't bring in symbols to satisfy
             undefined references in shared objects.  */
          if (h != (struct bfd_link_hash_entry *) NULL
-             && h->type == bfd_link_hash_undefined)
+             && h->type == bfd_link_hash_undefined
+             && (info->hash->creator != abfd->xvec
+                 || (((struct xcoff_link_hash_entry *) h)->flags
+                     & XCOFF_DEF_DYNAMIC) == 0))
            {
              if (! (*info->callbacks->add_archive_element) (info, abfd, name))
                return false;
@@ -855,6 +1227,91 @@ xcoff_link_check_ar_symbols (abfd, info, pneeded)
   return true;
 }
 
+/* Look through the loader symbols to see if this dynamic object
+   should be included in the link.  The native linker uses the loader
+   symbols, not the normal symbol table, so we do too.  */
+
+static boolean
+xcoff_link_check_dynamic_ar_symbols (abfd, info, pneeded)
+     bfd *abfd;
+     struct bfd_link_info *info;
+     boolean *pneeded;
+{
+  asection *lsec;
+  bfd_byte *buf;
+  struct internal_ldhdr ldhdr;
+  const char *strings;
+  struct external_ldsym *elsym, *elsymend;
+
+  *pneeded = false;
+
+  lsec = bfd_get_section_by_name (abfd, ".loader");
+  if (lsec == NULL)
+    {
+      /* There are no symbols, so don't try to include it.  */
+      return true;
+    }
+
+  if (! xcoff_get_section_contents (abfd, lsec))
+    return false;
+  buf = coff_section_data (abfd, lsec)->contents;
+
+  xcoff_swap_ldhdr_in (abfd, (struct external_ldhdr *) buf, &ldhdr);
+
+  strings = (char *) buf + ldhdr.l_stoff;
+
+  elsym = (struct external_ldsym *) (buf + LDHDRSZ);
+  elsymend = elsym + ldhdr.l_nsyms;
+  for (; elsym < elsymend; elsym++)
+    {
+      struct internal_ldsym ldsym;
+      char nambuf[SYMNMLEN + 1];
+      const char *name;
+      struct bfd_link_hash_entry *h;
+
+      xcoff_swap_ldsym_in (abfd, elsym, &ldsym);
+
+      /* We are only interested in exported symbols.  */
+      if ((ldsym.l_smtype & L_EXPORT) == 0)
+       continue;
+
+      if (ldsym._l._l_l._l_zeroes == 0)
+       name = strings + ldsym._l._l_l._l_offset;
+      else
+       {
+         memcpy (nambuf, ldsym._l._l_name, SYMNMLEN);
+         nambuf[SYMNMLEN] = '\0';
+         name = nambuf;
+       }
+
+      h = bfd_link_hash_lookup (info->hash, name, false, false, true);
+
+      /* We are only interested in symbols that are currently
+         undefined.  At this point we know that we are using an XCOFF
+         hash table.  */
+      if (h != NULL
+         && h->type == bfd_link_hash_undefined
+         && (((struct xcoff_link_hash_entry *) h)->flags
+             & XCOFF_DEF_DYNAMIC) == 0)
+       {
+         if (! (*info->callbacks->add_archive_element) (info, abfd, name))
+           return false;
+         *pneeded = true;
+         return true;
+       }
+    }
+
+  /* We do not need this shared object.  */
+
+  if (buf != NULL && ! coff_section_data (abfd, lsec)->keep_contents)
+    {
+      free (coff_section_data (abfd, lsec)->contents);
+      coff_section_data (abfd, lsec)->contents = NULL;
+    }
+
+  return true;
+}
+
 /* Returns the index of reloc in RELOCS with the least address greater
    than or equal to ADDRESS.  The relocs are sorted by address.  */
 
@@ -958,65 +1415,71 @@ xcoff_link_add_symbols (abfd, info)
        return false;
     }
 
-  /* We need to build a .loader section, so we do it here.  This won't
-     work if we're producing an XCOFF output file with no XCOFF input
-     files.  FIXME.  */
-  if (xcoff_hash_table (info)->loader_section == NULL)
+  if (info->hash->creator == abfd->xvec)
     {
-      asection *lsec;
+      /* We need to build a .loader section, so we do it here.  This
+        won't work if we're producing an XCOFF output file with no
+        XCOFF input files.  FIXME.  */
+      if (xcoff_hash_table (info)->loader_section == NULL)
+       {
+         asection *lsec;
 
-      lsec = bfd_make_section_anyway (abfd, ".loader");
-      if (lsec == NULL)
-       goto error_return;
-      xcoff_hash_table (info)->loader_section = lsec;
-      lsec->flags |= SEC_HAS_CONTENTS | SEC_IN_MEMORY;
-    }
-  /* Likewise for the linkage section.  */
-  if (xcoff_hash_table (info)->linkage_section == NULL)
-    {
-      asection *lsec;
+         lsec = bfd_make_section_anyway (abfd, ".loader");
+         if (lsec == NULL)
+           goto error_return;
+         xcoff_hash_table (info)->loader_section = lsec;
+         lsec->flags |= SEC_HAS_CONTENTS | SEC_IN_MEMORY;
+       }
+      /* Likewise for the linkage section.  */
+      if (xcoff_hash_table (info)->linkage_section == NULL)
+       {
+         asection *lsec;
 
-      lsec = bfd_make_section_anyway (abfd, ".gl");
-      if (lsec == NULL)
-       goto error_return;
-      xcoff_hash_table (info)->linkage_section = lsec;
-      lsec->flags |= SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY;
-      lsec->alignment_power = 2;
-    }
-  /* Likewise for the TOC section.  */
-  if (xcoff_hash_table (info)->toc_section == NULL)
-    {
-      asection *tsec;
+         lsec = bfd_make_section_anyway (abfd, ".gl");
+         if (lsec == NULL)
+           goto error_return;
+         xcoff_hash_table (info)->linkage_section = lsec;
+         lsec->flags |= (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
+                         | SEC_IN_MEMORY);
+         lsec->alignment_power = 2;
+       }
+      /* Likewise for the TOC section.  */
+      if (xcoff_hash_table (info)->toc_section == NULL)
+       {
+         asection *tsec;
 
-      tsec = bfd_make_section_anyway (abfd, ".tc");
-      if (tsec == NULL)
-       goto error_return;
-      xcoff_hash_table (info)->toc_section = tsec;
-      tsec->flags |= SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY;
-      tsec->alignment_power = 2;
-    }
-  /* Likewise for the descriptor section.  */
-  if (xcoff_hash_table (info)->descriptor_section == NULL)
-    {
-      asection *dsec;
+         tsec = bfd_make_section_anyway (abfd, ".tc");
+         if (tsec == NULL)
+           goto error_return;
+         xcoff_hash_table (info)->toc_section = tsec;
+         tsec->flags |= (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
+                         | SEC_IN_MEMORY);
+         tsec->alignment_power = 2;
+       }
+      /* Likewise for the descriptor section.  */
+      if (xcoff_hash_table (info)->descriptor_section == NULL)
+       {
+         asection *dsec;
 
-      dsec = bfd_make_section_anyway (abfd, ".ds");
-      if (dsec == NULL)
-       goto error_return;
-      xcoff_hash_table (info)->descriptor_section = dsec;
-      dsec->flags |= SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY;
-      dsec->alignment_power = 2;
-    }
-  /* Likewise for the .debug section.  */
-  if (xcoff_hash_table (info)->debug_section == NULL)
-    {
-      asection *dsec;
+         dsec = bfd_make_section_anyway (abfd, ".ds");
+         if (dsec == NULL)
+           goto error_return;
+         xcoff_hash_table (info)->descriptor_section = dsec;
+         dsec->flags |= (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
+                         | SEC_IN_MEMORY);
+         dsec->alignment_power = 2;
+       }
+      /* Likewise for the .debug section.  */
+      if (xcoff_hash_table (info)->debug_section == NULL)
+       {
+         asection *dsec;
 
-      dsec = bfd_make_section_anyway (abfd, ".debug");
-      if (dsec == NULL)
-       goto error_return;
-      xcoff_hash_table (info)->debug_section = dsec;
-      dsec->flags |= SEC_HAS_CONTENTS | SEC_IN_MEMORY;
+         dsec = bfd_make_section_anyway (abfd, ".debug");
+         if (dsec == NULL)
+           goto error_return;
+         xcoff_hash_table (info)->debug_section = dsec;
+         dsec->flags |= SEC_HAS_CONTENTS | SEC_IN_MEMORY;
+       }
     }
 
   if ((abfd->flags & DYNAMIC) != 0
@@ -1625,7 +2088,8 @@ xcoff_link_add_symbols (abfd, info)
 
       /* Check for magic symbol names.  */
       if ((smtyp == XTY_SD || smtyp == XTY_CM)
-         && aux.x_csect.x_smclas != XMC_TC)
+         && aux.x_csect.x_smclas != XMC_TC
+         && aux.x_csect.x_smclas != XMC_TD)
        {
          int i;
 
@@ -1666,12 +2130,25 @@ xcoff_link_add_symbols (abfd, info)
              || sym._n._n_n._n_offset == 0)
            copy = true;
 
+         /* The AIX linker appears to only detect multiple symbol
+            definitions when there is a reference to the symbol.  If
+            a symbol is defined multiple times, and the only
+            references are from the same object file, the AIX linker
+            appears to permit it.  It does not merge the different
+            definitions, but handles them independently.  On the
+            other hand, if there is a reference, the linker reports
+            an error.
+
+            This matters because the AIX <net/net_globals.h> header
+            file actually defines an initialized array, so we have to
+            actually permit that to work.
+
+            We also have to handle the case of statically linking a
+            shared object, which will cause symbol redefinitions,
+            although this is an easier case to detect.  */
+
          if (info->hash->creator == abfd->xvec)
            {
-             /* If we are statically linking a shared object, it is
-                 OK for symbol redefinitions to occur.  I can't figure
-                 out just what the XCOFF linker is doing, but
-                 something like this is required for -bnso to work.  */
              if (! bfd_is_und_section (section))
                *sym_hash = xcoff_link_hash_lookup (xcoff_hash_table (info),
                                                    name, true, copy, false);
@@ -1686,18 +2163,71 @@ xcoff_link_add_symbols (abfd, info)
                  && ! bfd_is_und_section (section)
                  && ! bfd_is_com_section (section))
                {
-                 if ((abfd->flags & DYNAMIC) != 0)
+                 /* This is a second definition of a defined symbol.  */
+                 if ((abfd->flags & DYNAMIC) != 0
+                     && ((*sym_hash)->smclas != XMC_GL
+                         || aux.x_csect.x_smclas == XMC_GL
+                         || ((*sym_hash)->root.u.def.section->owner->flags
+                             & DYNAMIC) == 0))
                    {
+                     /* The new symbol is from a shared library, and
+                         either the existing symbol is not global
+                         linkage code or this symbol is global linkage
+                         code.  If the existing symbol is global
+                         linkage code and the new symbol is not, then
+                         we want to use the new symbol.  */
                      section = bfd_und_section_ptr;
                      value = 0;
                    }
                  else if (((*sym_hash)->root.u.def.section->owner->flags
                            & DYNAMIC) != 0)
                    {
+                     /* The existing symbol is from a shared library.
+                         Replace it.  */
                      (*sym_hash)->root.type = bfd_link_hash_undefined;
                      (*sym_hash)->root.u.undef.abfd =
                        (*sym_hash)->root.u.def.section->owner;
                    }
+                 else if ((*sym_hash)->root.next != NULL
+                          || info->hash->undefs_tail == &(*sym_hash)->root)
+                   {
+                     /* This symbol has been referenced.  In this
+                         case, we just continue and permit the
+                         multiple definition error.  See the comment
+                         above about the behaviour of the AIX linker.  */
+                   }
+                 else if ((*sym_hash)->smclas == aux.x_csect.x_smclas)
+                   {
+                     /* The symbols are both csects of the same
+                         class.  There is at least a chance that this
+                         is a semi-legitimate redefinition.  */
+                     section = bfd_und_section_ptr;
+                     value = 0;
+                     (*sym_hash)->flags |= XCOFF_MULTIPLY_DEFINED;
+                   }
+               }
+             else if (((*sym_hash)->flags & XCOFF_MULTIPLY_DEFINED) != 0
+                      && ((*sym_hash)->root.type == bfd_link_hash_defined
+                          || (*sym_hash)->root.type == bfd_link_hash_defweak)
+                      && (bfd_is_und_section (section)
+                          || bfd_is_com_section (section)))
+               {
+                 /* This is a reference to a multiply defined symbol.
+                    Report the error now.  See the comment above
+                    about the behaviour of the AIX linker.  We could
+                    also do this with warning symbols, but I'm not
+                    sure the XCOFF linker is wholly prepared to
+                    handle them, and that would only be a warning,
+                    not an error.  */
+                 if (! ((*info->callbacks->multiple_definition)
+                        (info, (*sym_hash)->root.root.string,
+                         (bfd *) NULL, (asection *) NULL, 0,
+                         (*sym_hash)->root.u.def.section->owner,
+                         (*sym_hash)->root.u.def.section,
+                         (*sym_hash)->root.u.def.value)))
+                   goto error_return;
+                 /* Try not to give this error too many times.  */
+                 (*sym_hash)->flags &= ~XCOFF_MULTIPLY_DEFINED;
                }
            }
 
@@ -1763,7 +2293,7 @@ xcoff_link_add_symbols (abfd, info)
   /* Make sure that we have seen all the relocs.  */
   for (o = abfd->sections; o != first_csect; o = o->next)
     {
-      /* Reset the section size and the line numebr count, since the
+      /* Reset the section size and the line number count, since the
         data is now attached to the csects.  Don't reset the size of
         the .debug section, since we need to read it below in
         bfd_xcoff_size_dynamic_sections.  */
@@ -1903,7 +2433,7 @@ xcoff_link_add_dynamic_symbols (abfd, info)
      struct bfd_link_info *info;
 {
   asection *lsec;
-  bfd_byte *buf = NULL;
+  bfd_byte *buf;
   struct internal_ldhdr ldhdr;
   const char *strings;
   struct external_ldsym *elsym, *elsymend;
@@ -1922,7 +2452,7 @@ xcoff_link_add_dynamic_symbols (abfd, info)
        ("%s: XCOFF shared object when not producing XCOFF output",
         bfd_get_filename (abfd));
       bfd_set_error (bfd_error_invalid_operation);
-      goto error_return;
+      return false;
     }
 
   /* The symbols we use from a dynamic object are not the symbols in
@@ -1943,16 +2473,12 @@ xcoff_link_add_dynamic_symbols (abfd, info)
        ("%s: dynamic object with no .loader section",
         bfd_get_filename (abfd));
       bfd_set_error (bfd_error_no_symbols);
-      goto error_return;
+      return false;
     }
 
-  buf = (bfd_byte *) bfd_malloc (lsec->_raw_size);
-  if (buf == NULL && lsec->_raw_size > 0)
-    goto error_return;
-
-  if (! bfd_get_section_contents (abfd, lsec, (PTR) buf, (file_ptr) 0,
-                                 lsec->_raw_size))
-    goto error_return;
+  if (! xcoff_get_section_contents (abfd, lsec))
+    return false;
+  buf = coff_section_data (abfd, lsec)->contents;
 
   /* Remove the sections from this object, so that they do not get
      included in the link.  */
@@ -1995,7 +2521,7 @@ xcoff_link_add_dynamic_symbols (abfd, info)
       h = xcoff_link_hash_lookup (xcoff_hash_table (info), name, true,
                                  true, true);
       if (h == NULL)
-       goto error_return;
+       return false;
 
       h->flags |= XCOFF_DEF_DYNAMIC;
 
@@ -2036,10 +2562,10 @@ xcoff_link_add_dynamic_symbols (abfd, info)
        }
     }
 
-  if (buf != NULL)
+  if (buf != NULL && ! coff_section_data (abfd, lsec)->keep_contents)
     {
-      free (buf);
-      buf = NULL;
+      free (coff_section_data (abfd, lsec)->contents);
+      coff_section_data (abfd, lsec)->contents = NULL;
     }
 
   /* Record this file in the import files.  */
@@ -2047,7 +2573,7 @@ xcoff_link_add_dynamic_symbols (abfd, info)
   n = ((struct xcoff_import_file *)
        bfd_alloc (abfd, sizeof (struct xcoff_import_file)));
   if (n == NULL)
-    goto error_return;
+    return false;
   n->next = NULL;
 
   /* For some reason, the path entry in the import file list for a
@@ -2081,11 +2607,6 @@ xcoff_link_add_dynamic_symbols (abfd, info)
   xcoff_data (abfd)->import_file_id = c;
 
   return true;
-
- error_return:
-  if (buf != NULL)
-    free (buf);
-  return false;
 }
 \f
 /* Routines that are called after all the input files have been
@@ -2927,9 +3448,24 @@ xcoff_build_ldsyms (h, p)
   struct xcoff_loader_info *ldinfo = (struct xcoff_loader_info *) p;
   size_t len;
 
-  /* If all defined symbols should be exported, mark them now.  */
+  /* If this is a final link, and the symbol was defined as a common
+     symbol in a regular object file, and there was no definition in
+     any dynamic object, then the linker will have allocated space for
+     the symbol in a common section but the XCOFF_DEF_REGULAR flag
+     will not have been set.  */
+  if (h->root.type == bfd_link_hash_defined
+      && (h->flags & XCOFF_DEF_REGULAR) == 0
+      && (h->flags & XCOFF_REF_REGULAR) != 0
+      && (h->flags & XCOFF_DEF_DYNAMIC) == 0
+      && (h->root.u.def.section->owner->flags & DYNAMIC) == 0)
+    h->flags |= XCOFF_DEF_REGULAR;
+
+  /* If all defined symbols should be exported, mark them now.  We
+     don't want to export the actual functions, just the function
+     descriptors.  */
   if (ldinfo->export_defineds
-      && (h->flags & XCOFF_DEF_REGULAR) != 0)
+      && (h->flags & XCOFF_DEF_REGULAR) != 0
+      && h->root.root.string[0] != '.')
     h->flags |= XCOFF_EXPORT;
 
   /* We don't want to garbage collect symbols which are not defined in
@@ -3032,11 +3568,10 @@ xcoff_build_ldsyms (h, p)
       else
        {
          (*_bfd_error_handler)
-           ("attempt to export undefined symbol `%s'",
+           ("warning: attempt to export undefined symbol `%s'",
             h->root.root.string);
-         ldinfo->failed = true;
-         bfd_set_error (bfd_error_invalid_operation);
-         return false;
+         h->ldsym = NULL;
+         return true;
        }
     }
 
@@ -3217,6 +3752,12 @@ _bfd_xcoff_bfd_final_link (abfd, info)
 
              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;
@@ -3983,11 +4524,20 @@ xcoff_link_input_bfd (finfo, input_bfd)
                  of the TOC using a 16 bit offset from tocval.  This
                  test assumes that the TOC comes at the end of the
                  output section, as it does in the default linker
-                 script.  If the TOC anchor is too far into the .toc
-                 section, the relocation routine will report
-                 overflows.  */
+                 script.  */
+
              tocend = ((*csectpp)->output_section->vma
                        + (*csectpp)->output_section->_raw_size);
+
+             if (tocval + 0x10000 < tocend)
+               {
+                 (*_bfd_error_handler)
+                   ("TOC overflow: 0x%lx > 0x10000; try -mminimal-toc when compiling",
+                    (unsigned long) (tocend - tocval));
+                 bfd_set_error (bfd_error_file_too_big);
+                 return false;
+               }
+
              if (tocval + 0x8000 < tocend)
                {
                  bfd_vma tocadd;
@@ -4335,7 +4885,8 @@ xcoff_link_input_bfd (finfo, input_bfd)
 
                  if (ISFCN (isymp->n_type)
                      || ISTAG (isymp->n_sclass)
-                     || isymp->n_sclass == C_BLOCK)
+                     || isymp->n_sclass == C_BLOCK
+                     || isymp->n_sclass == C_FCN)
                    {
                      indx = aux.x_sym.x_fcnary.x_fcn.x_endndx.l;
                      if (indx > 0
@@ -4571,6 +5122,12 @@ xcoff_link_input_bfd (finfo, input_bfd)
     {
       bfd_byte *contents;
 
+      if (! o->linker_mark)
+       {
+         /* This section was omitted from the link.  */
+         continue;
+       }
+
       if ((o->flags & SEC_HAS_CONTENTS) == 0
          || o->_raw_size == 0
          || (o->flags & SEC_IN_MEMORY) != 0)
@@ -4628,6 +5185,7 @@ xcoff_link_input_bfd (finfo, input_bfd)
            {
              struct xcoff_link_hash_entry *h = NULL;
              struct internal_ldrel ldrel;
+             boolean quiet;
 
              *rel_hash = NULL;
 
@@ -4640,12 +5198,13 @@ xcoff_link_input_bfd (finfo, input_bfd)
              if (r_symndx != -1)
                {
                  h = obj_xcoff_sym_hashes (input_bfd)[r_symndx];
-                 if  (h != NULL
-                      && (irel->r_type == R_TOC
-                          || irel->r_type == R_GL
-                          || irel->r_type == R_TCL
-                          || irel->r_type == R_TRL
-                          || irel->r_type == R_TRLA))
+                 if (h != NULL
+                     && h->smclas != XMC_TD
+                     && (irel->r_type == R_TOC
+                         || irel->r_type == R_GL
+                         || irel->r_type == R_TCL
+                         || irel->r_type == R_TRL
+                         || irel->r_type == R_TRLA))
                    {
                      /* This is a TOC relative reloc with a symbol
                          attached.  The symbol should be the one which
@@ -4752,6 +5311,7 @@ xcoff_link_input_bfd (finfo, input_bfd)
                    }
                }
 
+             quiet = false;
              switch (irel->r_type)
                {
                default:
@@ -4803,7 +5363,17 @@ xcoff_link_input_bfd (finfo, input_bfd)
                    }
                  else
                    {
-                     if (h->ldindx < 0)
+                     if (! finfo->info->relocateable
+                         && (h->flags & XCOFF_DEF_DYNAMIC) == 0
+                         && (h->flags & XCOFF_IMPORT) == 0)
+                       {
+                         /* We already called the undefined_symbol
+                            callback for this relocation, in
+                            _bfd_ppc_xcoff_relocate_section.  Don't
+                            issue any more warnings.  */
+                         quiet = true;
+                       }
+                     if (h->ldindx < 0 && ! quiet)
                        {
                          (*_bfd_error_handler)
                            ("%s: `%s' in loader reloc but not loader sym",
@@ -4817,7 +5387,8 @@ xcoff_link_input_bfd (finfo, input_bfd)
                  ldrel.l_rtype = (irel->r_size << 8) | irel->r_type;
                  ldrel.l_rsecnm = o->output_section->target_index;
                  if (xcoff_hash_table (finfo->info)->textro
-                     && strcmp (o->output_section->name, ".text") == 0)
+                     && strcmp (o->output_section->name, ".text") == 0
+                     && ! quiet)
                    {
                      (*_bfd_error_handler)
                        ("%s: loader reloc in read-only section %s",
@@ -5588,13 +6159,16 @@ _bfd_ppc_xcoff_relocate_section (output_bfd, info, input_bfd,
              /* Every symbol in a shared object is defined somewhere.  */
              val = 0;
            }
-         else if (! info->relocateable
-                  && ! info->shared)
+         else if (! info->relocateable)
            {
              if (! ((*info->callbacks->undefined_symbol)
                     (info, h->root.root.string, input_bfd, input_section,
                      rel->r_vaddr - input_section->vma)))
                return false;
+
+             /* Don't try to process the reloc.  It can't help, and
+                 it may generate another error.  */
+             continue;
            }
        }
 
@@ -5657,21 +6231,23 @@ _bfd_ppc_xcoff_relocate_section (output_bfd, info, input_bfd,
              address instruction which may be changed to a load
              instruction.  FIXME: I don't know if this is the correct
              implementation.  */
-         if (h != NULL && h->toc_section == NULL)
-           {
-             (*_bfd_error_handler)
-               ("%s: TOC reloc at 0x%x to symbol `%s' with no TOC entry",
-                bfd_get_filename (input_bfd), rel->r_vaddr,
-                h->root.root.string);
-             bfd_set_error (bfd_error_bad_value);
-             return false;
-           }
-         if (h != NULL)
+         if (h != NULL && h->smclas != XMC_TD)
            {
+             if (h->toc_section == NULL)
+               {
+                 (*_bfd_error_handler)
+                   ("%s: TOC reloc at 0x%x to symbol `%s' with no TOC entry",
+                    bfd_get_filename (input_bfd), rel->r_vaddr,
+                    h->root.root.string);
+                 bfd_set_error (bfd_error_bad_value);
+                 return false;
+               }
+
              BFD_ASSERT ((h->flags & XCOFF_SET_TOC) == 0);
              val = (h->toc_section->output_section->vma
                     + h->toc_section->output_offset);
            }
+
          val = ((val - xcoff_data (output_bfd)->toc)
                 - (sym->n_value - xcoff_data (input_bfd)->toc));
          addend = 0;
@@ -5744,7 +6320,11 @@ _bfd_ppc_xcoff_relocate_section (output_bfd, info, input_bfd,
 
          pnext = contents + (rel->r_vaddr - input_section->vma) + 4;
          next = bfd_get_32 (input_bfd, pnext);
-         if (h->smclas == XMC_GL)
+
+         /* The _ptrgl function is magic.  It is used by the AIX
+             compiler to call a function through a pointer.  */
+         if (h->smclas == XMC_GL
+             || strcmp (h->root.root.string, "._ptrgl") == 0)
            {
              if (next == 0x4def7b82            /* cror 15,15,15 */
                  || next == 0x4ffffb82)        /* cror 31,31,31 */
This page took 0.034986 seconds and 4 git commands to generate.