* xcofflink.c (XCOFF_DESCRIPTOR): Define.
authorIan Lance Taylor <ian@airs.com>
Thu, 9 Nov 1995 18:08:56 +0000 (18:08 +0000)
committerIan Lance Taylor <ian@airs.com>
Thu, 9 Nov 1995 18:08:56 +0000 (18:08 +0000)
(struct xcoff_link_hash_table): Add descriptor_section and
special_sections fields.
(_bfd_xcoff_bfd_link_hash_table_create): Initialize new fields.
(xcoff_link_add_symbols): Set linkage section alignment.  Create
descriptor section.  Check for magic symbol names (_text, etc.),
and record them in special_sections if found.  Set
XCOFF_DESCRIPTOR flag for a function descriptor, and set its
descriptor field to point back to the function code symbol.
(xcoff_sweep): Always mark the special descriptor_section.
(bfd_xcoff_export_symbol): Check whether the symbol might be a
function descriptor, and mark it if it is.
(bfd_xcoff_size_dynamic_sections): Add new special_sections
parameter, and fill it in.  Allocate space for the descriptor
section.
(xcoff_build_ldsyms): Set XCOFF_DEF_REGULAR flag when defining
global linkage code.  If an undefined function descriptor is
exported, arrange to define it.  Warn about any other undefined
exported symbol.
(_bfd_xcoff_bfd_final_link): Write out the descriptor section.
(xcoff_write_global_symbol): Create a function descriptor when
necessary.
* bfd-in.h (bfd_xcoff_size_dynamic_sections): Update declaration.
* bfd-in2.h: Rebuild.

bfd/ChangeLog
bfd/xcofflink.c

index e7641b8..ced5285 100644 (file)
@@ -1,3 +1,30 @@
+Thu Nov  9 13:01:31 1995  Ian Lance Taylor  <ian@cygnus.com>
+
+       * xcofflink.c (XCOFF_DESCRIPTOR): Define.
+       (struct xcoff_link_hash_table): Add descriptor_section and
+       special_sections fields.
+       (_bfd_xcoff_bfd_link_hash_table_create): Initialize new fields.
+       (xcoff_link_add_symbols): Set linkage section alignment.  Create
+       descriptor section.  Check for magic symbol names (_text, etc.),
+       and record them in special_sections if found.  Set
+       XCOFF_DESCRIPTOR flag for a function descriptor, and set its
+       descriptor field to point back to the function code symbol.
+       (xcoff_sweep): Always mark the special descriptor_section.
+       (bfd_xcoff_export_symbol): Check whether the symbol might be a
+       function descriptor, and mark it if it is.
+       (bfd_xcoff_size_dynamic_sections): Add new special_sections
+       parameter, and fill it in.  Allocate space for the descriptor
+       section.
+       (xcoff_build_ldsyms): Set XCOFF_DEF_REGULAR flag when defining
+       global linkage code.  If an undefined function descriptor is
+       exported, arrange to define it.  Warn about any other undefined
+       exported symbol.
+       (_bfd_xcoff_bfd_final_link): Write out the descriptor section.
+       (xcoff_write_global_symbol): Create a function descriptor when
+       necessary.
+       * bfd-in.h (bfd_xcoff_size_dynamic_sections): Update declaration.
+       * bfd-in2.h: Rebuild.
+
 Thu Nov  9 08:40:23 1995  Kim Knuttila  <krk@cygnus.com>
 
        * coff-ppc.c (ppc_coff_link_hash_entry): new types for hashing
index fd1ed7e..ca0b27b 100644 (file)
@@ -261,7 +261,9 @@ struct xcoff_link_hash_entry
     } u;
 
   /* If this symbol is a function entry point which is called, this
-     field holds a pointer to the function descriptor.  */
+     field holds a pointer to the function descriptor.  If this symbol
+     is a function descriptor, this field holds a pointer to the
+     function entry point.  */
   struct xcoff_link_hash_entry *descriptor;
 
   /* The .loader symbol table entry, if there is one.  */
@@ -296,6 +298,8 @@ struct xcoff_link_hash_entry
 #define XCOFF_MARK (02000)
   /* Symbol size is recorded in size_list list from hash table.  */
 #define XCOFF_HAS_SIZE (04000)
+  /* Symbol is a function descriptor.  */
+#define XCOFF_DESCRIPTOR (010000)
 
   /* The storage mapping class.  */
   unsigned char smclas;
@@ -332,6 +336,10 @@ struct xcoff_link_hash_table
      linkage code.  */
   asection *toc_section;
 
+  /* The .ds section we use to hold function descriptors which we
+     create for exported symbols.  */
+  asection *descriptor_section;
+
   /* The list of import files.  */
   struct xcoff_import_file *imports;
 
@@ -351,6 +359,9 @@ struct xcoff_link_hash_table
       struct xcoff_link_hash_entry *h;
       bfd_size_type size;
     } *size_list;
+
+  /* Magic sections: _text, _etext, _data, _edata, _end, end.  */
+  asection *special_sections[6];
 };
 
 /* Information we keep for each section in the output file during the
@@ -627,10 +638,12 @@ _bfd_xcoff_bfd_link_hash_table_create (abfd)
   memset (&ret->ldhdr, 0, sizeof (struct internal_ldhdr));
   ret->linkage_section = NULL;
   ret->toc_section = NULL;
+  ret->descriptor_section = NULL;
   ret->imports = NULL;
   ret->file_align = 0;
   ret->textro = false;
   ret->gc = false;
+  memset (ret->special_sections, 0, sizeof ret->special_sections);
 
   /* The linker will always generate a full a.out header.  We need to
      record that fact now, before the sizeof_headers routine could be
@@ -978,6 +991,7 @@ xcoff_link_add_symbols (abfd, info)
        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)
@@ -991,6 +1005,18 @@ xcoff_link_add_symbols (abfd, info)
       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)
     {
@@ -1623,6 +1649,33 @@ xcoff_link_add_symbols (abfd, info)
          break;
        }
 
+      /* Check for magic symbol names.  */
+      if ((smtyp == XTY_SD || smtyp == XTY_CM)
+         && aux.x_csect.x_smclas != XMC_TC)
+       {
+         int i;
+
+         i = -1;
+         if (name[0] == '_')
+           {
+             if (strcmp (name, "_text") == 0)
+               i = 0;
+             else if (strcmp (name, "_etext") == 0)
+               i = 1;
+             else if (strcmp (name, "_data") == 0)
+               i = 2;
+             else if (strcmp (name, "_edata") == 0)
+               i = 3;
+             else if (strcmp (name, "_end") == 0)
+               i = 4;
+           }
+         else if (name[0] == 'e' && strcmp (name, "end") == 0)
+           i = 5;
+
+         if (i != -1)
+           xcoff_hash_table (info)->special_sections[i] = csect;
+       }
+
       /* Now we have enough information to add the symbol to the
          linker hash table.  */
 
@@ -1800,6 +1853,10 @@ xcoff_link_add_symbols (abfd, info)
                                  (struct bfd_link_hash_entry **) &hds)))
                            goto error_return;
                        }
+                     hds->flags |= XCOFF_DESCRIPTOR;
+                     BFD_ASSERT ((hds->flags & XCOFF_CALLED) == 0
+                                 && (h->flags & XCOFF_DESCRIPTOR) == 0);
+                     hds->descriptor = h;
                      h->descriptor = hds;
                    }
                }
@@ -2250,6 +2307,7 @@ xcoff_sweep (info)
                  || o == xcoff_hash_table (info)->loader_section
                  || o == xcoff_hash_table (info)->linkage_section
                  || o == xcoff_hash_table (info)->toc_section
+                 || o == xcoff_hash_table (info)->descriptor_section
                  || strcmp (o->name, ".debug") == 0)
                o->flags |= SEC_MARK;
              else
@@ -2411,10 +2469,51 @@ bfd_xcoff_export_symbol (output_bfd, info, harg, syscall)
   /* FIXME: I'm not at all sure what syscall is supposed to mean, so
      I'm just going to ignore it until somebody explains it.  */
 
+  /* See if this is a function descriptor.  It may be one even though
+     it is not so marked.  */
+  if ((h->flags & XCOFF_DESCRIPTOR) == 0
+      && h->root.root.string[0] != '.')
+    {
+      char *fnname;
+      struct xcoff_link_hash_entry *hfn;
+
+      fnname = (char *) malloc (strlen (h->root.root.string + 2));
+      if (fnname == NULL)
+       {
+         bfd_set_error (bfd_error_no_memory);
+         return false;
+       }
+      fnname[0] = '.';
+      strcpy (fnname + 1, h->root.root.string);
+      hfn = xcoff_link_hash_lookup (xcoff_hash_table (info),
+                                   fnname, false, false, true);
+      free (fnname);
+      if (hfn != NULL
+         && hfn->smclas == XMC_PR
+         && (hfn->root.type == bfd_link_hash_defined
+             || hfn->root.type == bfd_link_hash_defweak))
+       {
+         h->flags |= XCOFF_DESCRIPTOR;
+         h->descriptor = hfn;
+         hfn->descriptor = h;
+       }
+    }
+
   /* Make sure we don't garbage collect this symbol.  */
   if (! xcoff_mark_symbol (info, h))
     return false;
 
+  /* If this is a function descriptor, make sure we don't garbage
+     collect the associated function code.  We normally don't have to
+     worry about this, because the descriptor will be attached to a
+     section with relocs, but if we are creating the descriptor
+     ourselves those relocs will not be visible to the mark code.  */
+  if ((h->flags & XCOFF_DESCRIPTOR) != 0)
+    {
+      if (! xcoff_mark_symbol (info, h->descriptor))
+       return false;
+    }
+
   return true;
 }
 
@@ -2507,7 +2606,7 @@ struct xcoff_loader_info
 boolean
 bfd_xcoff_size_dynamic_sections (output_bfd, info, libpath, entry,
                                 file_align, maxstack, maxdata, gc,
-                                modtype, textro)
+                                modtype, textro, special_sections)
      bfd *output_bfd;
      struct bfd_link_info *info;
      const char *libpath;
@@ -2518,10 +2617,12 @@ bfd_xcoff_size_dynamic_sections (output_bfd, info, libpath, entry,
      boolean gc;
      int modtype;
      boolean textro;
+     asection **special_sections;
 {
   struct xcoff_link_hash_entry *hentry;
   asection *lsec;
   struct xcoff_loader_info ldinfo;
+  int i;
   size_t impsize, impcount;
   struct xcoff_import_file *fl;
   struct internal_ldhdr *ldhdr;
@@ -2595,6 +2696,19 @@ bfd_xcoff_size_dynamic_sections (output_bfd, info, libpath, entry,
       xcoff_hash_table (info)->gc = true;
     }
 
+  /* Return special sections to the caller.  */
+  for (i = 0; i < 6; i++)
+    {
+      asection *sec;
+
+      sec = xcoff_hash_table (info)->special_sections[i];
+      if (sec != NULL
+         && gc
+         && (sec->flags & SEC_MARK) == 0)
+       sec = NULL;
+      special_sections[i] = sec;
+    }
+
   if (info->input_bfds == NULL)
     {
       /* I'm not sure what to do in this bizarre case.  */
@@ -2694,8 +2808,7 @@ bfd_xcoff_size_dynamic_sections (output_bfd, info, libpath, entry,
      when the corresponding normal relocs are handled in
      xcoff_link_input_bfd.  */
 
-  /* Allocate space for the global linkage section and the global toc
-     section.  */
+  /* Allocate space for the magic sections.  */
   sec = xcoff_hash_table (info)->linkage_section;
   if (sec->_raw_size > 0)
     {
@@ -2716,6 +2829,16 @@ bfd_xcoff_size_dynamic_sections (output_bfd, info, libpath, entry,
          goto error_return;
        }
     }
+  sec = xcoff_hash_table (info)->descriptor_section;
+  if (sec->_raw_size > 0)
+    {
+      sec->contents = (bfd_byte *) bfd_zalloc (output_bfd, sec->_raw_size);
+      if (sec->contents == NULL)
+       {
+         bfd_set_error (bfd_error_no_memory);
+         goto error_return;
+       }
+    }
 
   /* Now that we've done garbage collection, figure out the contents
      of the .debug section.  */
@@ -2877,6 +3000,7 @@ xcoff_build_ldsyms (h, p)
       h->root.u.def.section = sec;
       h->root.u.def.value = sec->_raw_size;
       h->smclas = XMC_GL;
+      h->flags |= XCOFF_DEF_REGULAR;
       sec->_raw_size += XCOFF_GLINK_SIZE;
 
       /* The global linkage code requires a TOC entry for the
@@ -2902,6 +3026,53 @@ xcoff_build_ldsyms (h, p)
        }
     }
 
+  /* If this symbol is exported, but not defined, we need to try to
+     define it.  */
+  if ((h->flags & XCOFF_EXPORT) != 0
+      && (h->flags & XCOFF_IMPORT) == 0
+      && (h->flags & XCOFF_DEF_REGULAR) == 0
+      && (h->flags & XCOFF_DEF_DYNAMIC) == 0
+      && (h->root.type == bfd_link_hash_undefined
+         || h->root.type == bfd_link_hash_undefweak))
+    {
+      if ((h->flags & XCOFF_DESCRIPTOR) != 0
+         && (h->descriptor->root.type == bfd_link_hash_defined
+             || h->descriptor->root.type == bfd_link_hash_defweak))
+       {
+         asection *sec;
+
+         /* This is an undefined function descriptor associated with
+             a defined entry point.  We can build up a function
+             descriptor ourselves.  Believe it or not, the AIX linker
+             actually does this, and there are cases where we need to
+             do it as well.  */
+         sec = xcoff_hash_table (ldinfo->info)->descriptor_section;
+         h->root.type = bfd_link_hash_defined;
+         h->root.u.def.section = sec;
+         h->root.u.def.value = sec->_raw_size;
+         h->smclas = XMC_DS;
+         h->flags |= XCOFF_DEF_REGULAR;
+         sec->_raw_size += 12;
+
+         /* A function descriptor uses two relocs: one for the
+             associated code, and one for the TOC address.  */
+         xcoff_hash_table (ldinfo->info)->ldrel_count += 2;
+         sec->reloc_count += 2;
+
+         /* We handle writing out the contents of the descriptor in
+             xcoff_write_global_symbol.  */
+       }
+      else
+       {
+         (*_bfd_error_handler)
+           ("attempt to export undefined symbol `%s'",
+            h->root.root.string);
+         ldinfo->failed = true;
+         bfd_set_error (bfd_error_invalid_operation);
+         return false;
+       }
+    }
+
   /* If this is still a common symbol, and it wasn't garbage
      collected, we need to actually allocate space for it in the .bss
      section.  */
@@ -3528,7 +3699,7 @@ _bfd_xcoff_bfd_final_link (abfd, info)
                                  o->_raw_size))
     goto error_return;
 
-  /* Write out the global linkage section and the toc section.  */
+  /* Write out the magic sections.  */
   o = xcoff_hash_table (info)->linkage_section;
   if (o->_raw_size > 0
       && ! bfd_set_section_contents (abfd, o->output_section, o->contents,
@@ -3539,6 +3710,11 @@ _bfd_xcoff_bfd_final_link (abfd, info)
       && ! bfd_set_section_contents (abfd, o->output_section, o->contents,
                                     o->output_offset, o->_raw_size))
     goto error_return;
+  o = xcoff_hash_table (info)->descriptor_section;
+  if (o->_raw_size > 0
+      && ! bfd_set_section_contents (abfd, o->output_section, o->contents,
+                                    o->output_offset, o->_raw_size))
+    goto error_return;
 
   /* Write out the string table.  */
   if (bfd_seek (abfd,
@@ -4857,6 +5033,109 @@ xcoff_write_global_symbol (h, p)
       ++finfo->ldrel;
     }
 
+  /* If this symbol is a specially defined function descriptor, write
+     it out.  The first word is the address of the function code
+     itself, the second word is the address of the TOC, and the third
+     word is zero.  */
+  if ((h->flags & XCOFF_DESCRIPTOR) != 0
+      && h->root.type == bfd_link_hash_defined
+      && (h->root.u.def.section
+         == xcoff_hash_table (finfo->info)->descriptor_section))
+    {
+      asection *sec;
+      asection *osec;
+      int oindx;
+      bfd_byte *p;
+      struct xcoff_link_hash_entry *hentry;
+      asection *esec;
+      struct internal_reloc *irel;
+      struct internal_ldrel ldrel;
+      asection *tsec;
+
+      sec = h->root.u.def.section;
+      osec = sec->output_section;
+      oindx = osec->target_index;
+      p = sec->contents + h->root.u.def.value;
+
+      hentry = h->descriptor;
+      BFD_ASSERT (hentry != NULL
+                 && (hentry->root.type == bfd_link_hash_defined
+                     || hentry->root.type == bfd_link_hash_defweak));
+      esec = hentry->root.u.def.section;
+      bfd_put_32 (output_bfd,
+                 (esec->output_section->vma
+                  + esec->output_offset
+                  + hentry->root.u.def.value),
+                 p);
+
+      irel = finfo->section_info[oindx].relocs + osec->reloc_count;
+      irel->r_vaddr = (osec->vma
+                      + sec->output_offset
+                      + h->root.u.def.value);
+      irel->r_symndx = esec->output_section->target_index;
+      irel->r_type = R_POS;
+      irel->r_size = 31;
+      finfo->section_info[oindx].rel_hashes[osec->reloc_count] = NULL;
+      ++osec->reloc_count;
+
+      ldrel.l_vaddr = irel->r_vaddr;
+      if (strcmp (esec->output_section->name, ".text") == 0)
+       ldrel.l_symndx = 0;
+      else if (strcmp (esec->output_section->name, ".data") == 0)
+       ldrel.l_symndx = 1;
+      else if (strcmp (esec->output_section->name, ".bss") == 0)
+       ldrel.l_symndx = 2;
+      else
+       {
+         (*_bfd_error_handler)
+           ("%s: loader reloc in unrecognized section `%s'",
+            bfd_get_filename (output_bfd),
+            esec->output_section->name);
+         bfd_set_error (bfd_error_nonrepresentable_section);
+         return false;
+       }
+      ldrel.l_rtype = (31 << 8) | R_POS;
+      ldrel.l_rsecnm = oindx;
+      xcoff_swap_ldrel_out (output_bfd, &ldrel, finfo->ldrel);
+      ++finfo->ldrel;
+
+      bfd_put_32 (output_bfd, xcoff_data (output_bfd)->toc, p + 4);
+
+      tsec = xcoff_data (output_bfd)->toc_section;
+
+      ++irel;
+      irel->r_vaddr = (osec->vma
+                      + sec->output_offset
+                      + h->root.u.def.value
+                      + 4);
+      irel->r_symndx = tsec->output_section->target_index;
+      irel->r_type = R_POS;
+      irel->r_size = 31;
+      finfo->section_info[oindx].rel_hashes[osec->reloc_count] = NULL;
+      ++osec->reloc_count;
+
+      ldrel.l_vaddr = irel->r_vaddr;
+      if (strcmp (tsec->output_section->name, ".text") == 0)
+       ldrel.l_symndx = 0;
+      else if (strcmp (tsec->output_section->name, ".data") == 0)
+       ldrel.l_symndx = 1;
+      else if (strcmp (tsec->output_section->name, ".bss") == 0)
+       ldrel.l_symndx = 2;
+      else
+       {
+         (*_bfd_error_handler)
+           ("%s: loader reloc in unrecognized section `%s'",
+            bfd_get_filename (output_bfd),
+            tsec->output_section->name);
+         bfd_set_error (bfd_error_nonrepresentable_section);
+         return false;
+       }
+      ldrel.l_rtype = (31 << 8) | R_POS;
+      ldrel.l_rsecnm = oindx;
+      xcoff_swap_ldrel_out (output_bfd, &ldrel, finfo->ldrel);
+      ++finfo->ldrel;
+    }
+
   if (h->indx >= 0)
     return true;