Accept mips-sgi-irix output in a few ld tests
[deliverable/binutils-gdb.git] / ld / ldctor.c
index 2a7e9b01355f7069966859338b2f1dffa57ea550..881ca258cbc2d403eeaa1da2c70ee858da5adead 100644 (file)
-/* Copyright (C) 1991 Free Software Foundation, Inc.
-   
-This file is part of GLD, the Gnu Linker.
+/* ldctor.c -- constructor support routines
+   Copyright (C) 1991-2019 Free Software Foundation, Inc.
+   By Steve Chamberlain <sac@cygnus.com>
 
-GLD is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 1, or (at your option)
-any later version.
+   This file is part of the GNU Binutils.
 
-GLD is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
 
-You should have received a copy of the GNU General Public License
-along with GLD; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
 
-/*
- * By steve chamberlain
- * steve@cygnus.com
- */
+   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., 51 Franklin Street - Fifth Floor, Boston,
  MA 02110-1301, USA.  */
 
+#include "sysdep.h"
 #include "bfd.h"
-#include "sysdep.h" 
+#include "bfdlink.h"
+#include "safe-ctype.h"
+#include "ctf-api.h"
+
 #include "ld.h"
 #include "ldexp.h"
 #include "ldlang.h"
-#include "ldsym.h"
 #include "ldmisc.h"
-#include "ldgram.h"
+#include <ldgram.h>
+#include "ldmain.h"
+#include "ldctor.h"
 
-/* exported list of statements needed to handle constructors */
+/* The list of statements needed to handle constructors.  These are
+   invoked by the command CONSTRUCTORS in the linker script.  */
 lang_statement_list_type constructor_list;
 
+/* Whether the constructors should be sorted.  Note that this is
+   global for the entire link; we assume that there is only a single
+   CONSTRUCTORS command in the linker script.  */
+bfd_boolean constructors_sorted;
 
+/* The sets we have seen.  */
+struct set_info *sets;
 
-typedef struct constructor_list 
-{
-   CONST char *name;
-    struct constructor_list *next;
-}  constructor_list_type;
-   
-static constructor_list_type *constructor_name_list;
-
-static void
-add_constructor_name (name)
-     CONST char *name;
+/* Add an entry to a set.  H is the entry in the linker hash table.
+   RELOC is the relocation to use for an entry in the set.  SECTION
+   and VALUE are the value to add.  This is called during the first
+   phase of the link, when we are still gathering symbols together.
+   We just record the information now.  The ldctor_build_sets
+   function will construct the sets.  */
+
+void
+ldctor_add_set_entry (struct bfd_link_hash_entry *h,
+                     bfd_reloc_code_real_type reloc,
+                     const char *name,
+                     asection *section,
+                     bfd_vma value)
 {
-    register constructor_list_type *ptr = constructor_name_list;
-    for (; ptr != (constructor_list_type *)NULL; ptr = ptr->next) {
-       if (strcmp (ptr->name, name) == 0) 
-           return;
+  struct set_info *p;
+  struct set_element *e;
+  struct set_element **epp;
+
+  for (p = sets; p != NULL; p = p->next)
+    if (p->h == h)
+      break;
+
+  if (p == NULL)
+    {
+      p = (struct set_info *) xmalloc (sizeof (struct set_info));
+      p->next = sets;
+      sets = p;
+      p->h = h;
+      p->reloc = reloc;
+      p->count = 0;
+      p->elements = NULL;
     }
+  else
+    {
+      if (p->reloc != reloc)
+       {
+         einfo (_("%X%P: different relocs used in set %s\n"),
+                h->root.string);
+         return;
+       }
+
+      /* Don't permit a set to be constructed from different object
+        file formats.  The same reloc may have different results.  We
+        actually could sometimes handle this, but the case is
+        unlikely to ever arise.  Sometimes constructor symbols are in
+        unusual sections, such as the absolute section--this appears
+        to be the case in Linux a.out--and in such cases we just
+        assume everything is OK.  */
+      if (p->elements != NULL
+         && section->owner != NULL
+         && p->elements->section->owner != NULL
+         && strcmp (bfd_get_target (section->owner),
+                    bfd_get_target (p->elements->section->owner)) != 0)
+       {
+         einfo (_("%X%P: different object file formats composing set %s\n"),
+                h->root.string);
+         return;
+       }
+    }
+
+  e = (struct set_element *) xmalloc (sizeof (struct set_element));
+  e->u.next = NULL;
+  e->name = name;
+  e->section = section;
+  e->value = value;
 
-    /* There isn't an entry, so add one */
-    ptr = (constructor_list_type *) ldmalloc (sizeof(constructor_list_type));
-    ptr->next = constructor_name_list;
-    ptr->name = name;
-    constructor_name_list = ptr;
+  for (epp = &p->elements; *epp != NULL; epp = &(*epp)->u.next)
+    ;
+  *epp = e;
+
+  ++p->count;
 }
 
-void
-ldlang_add_constructor (name)
-     ldsym_type *name;
+/* Get the priority of a g++ global constructor or destructor from the
+   symbol name.  */
+
+static int
+ctor_prio (const char *name)
 {
-  if (name->flags & SYM_CONSTRUCTOR) return;
-  add_constructor_name (name->name);
-  name->flags |= SYM_CONSTRUCTOR;
+  /* The name will look something like _GLOBAL_$I$65535$test02__Fv.
+     There might be extra leading underscores, and the $ characters
+     might be something else.  The I might be a D.  */
+
+  while (*name == '_')
+    ++name;
+
+  if (!CONST_STRNEQ (name, "GLOBAL_"))
+    return -1;
+
+  name += sizeof "GLOBAL_" - 1;
+
+  if (name[0] != name[2])
+    return -1;
+  if (name[1] != 'I' && name[1] != 'D')
+    return -1;
+  if (!ISDIGIT (name[3]))
+    return -1;
+
+  return atoi (name + 3);
 }
 
+/* This function is used to sort constructor elements by priority.  It
+   is called via qsort.  */
+
+static int
+ctor_cmp (const void *p1, const void *p2)
+{
+  const struct set_element *pe1 = *(const struct set_element **) p1;
+  const struct set_element *pe2 = *(const struct set_element **) p2;
+  const char *n1;
+  const char *n2;
+  int prio1;
+  int prio2;
+
+  n1 = pe1->name;
+  if (n1 == NULL)
+    n1 = "";
+  n2 = pe2->name;
+  if (n2 == NULL)
+    n2 = "";
+
+  /* We need to sort in reverse order by priority.  When two
+     constructors have the same priority, we should maintain their
+     current relative position.  */
+
+  prio1 = ctor_prio (n1);
+  prio2 = ctor_prio (n2);
+
+  /* We sort in reverse order because that is what g++ expects.  */
+  if (prio1 < prio2)
+    return 1;
+  if (prio1 > prio2)
+    return -1;
+
+  /* Force a stable sort.  */
+  if (pe1->u.idx < pe2->u.idx)
+    return -1;
+  if (pe1->u.idx > pe2->u.idx)
+    return 1;
+  return 0;
+}
 
-/* this function looks through the sections attached to the supplied
-   bfd to see if any of them are magical constructor sections. If so
-   their names are remembered and added to the list of constructors */
+/* This function is called after the first phase of the link and
+   before the second phase.  At this point all set information has
+   been gathered.  We now put the statements to build the sets
+   themselves into constructor_list.  */
 
 void
-ldlang_check_for_constructors (entry)
-     struct lang_input_statement_struct *entry;
+ldctor_build_sets (void)
 {
-    asection *section;
+  static bfd_boolean called;
+  bfd_boolean header_printed;
+  struct set_info *p;
 
-    for (section = entry->the_bfd->sections;
-        section != (asection *)NULL;
-        section = section->next) 
+  /* The emulation code may call us directly, but we only want to do
+     this once.  */
+  if (called)
+    return;
+  called = TRUE;
+
+  if (constructors_sorted)
     {
-       if (section->flags & SEC_CONSTRUCTOR) 
-           add_constructor_name (section->name);
-    }
-}
+      for (p = sets; p != NULL; p = p->next)
+       {
+         int c, i;
+         struct set_element *e, *enext;
+         struct set_element **array;
 
+         if (p->elements == NULL)
+           continue;
 
-/* run through the symbol table, find all the symbols which are
-   constructors and for each one, create statements to do something
-   like..
+         c = 0;
+         for (e = p->elements; e != NULL; e = e->u.next)
+           ++c;
 
-   for something like "__CTOR_LIST__, foo" in the assembler
+         array = (struct set_element **) xmalloc (c * sizeof *array);
 
-   __CTOR_LIST__ = . ;
-   LONG(__CTOR_LIST_END - . / 4 - 2)
-   *(foo)
-   __CTOR_LIST_END= .
+         i = 0;
+         for (e = p->elements; e != NULL; e = enext)
+           {
+             array[i] = e;
+             enext = e->u.next;
+             e->u.idx = i;
+             ++i;
+           }
 
-   Put these statements onto a special list.
+         qsort (array, c, sizeof *array, ctor_cmp);
 
-*/
+         e = array[0];
+         p->elements = e;
+         for (i = 0; i < c - 1; i++)
+           array[i]->u.next = array[i + 1];
+         array[i]->u.next = NULL;
 
+         free (array);
+       }
+    }
 
-void
-find_constructors ()
-{
-    lang_statement_list_type *old = stat_ptr;
-    constructor_list_type *p = constructor_name_list;
-    stat_ptr = & constructor_list;
-    lang_list_init(stat_ptr);
-    while (p != (constructor_list_type *)NULL) 
+  lang_list_init (&constructor_list);
+  push_stat_ptr (&constructor_list);
+
+  header_printed = FALSE;
+  for (p = sets; p != NULL; p = p->next)
     {
-       /* Have we already done this one ? */
-       CONST char *name = p->name;
-       ldsym_type *lookup = ldsym_get_soft(name);
+      struct set_element *e;
+      reloc_howto_type *howto;
+      int reloc_size, size;
+
+      /* If the symbol is defined, we may have been invoked from
+        collect, and the sets may already have been built, so we do
+        not do anything.  */
+      if (p->h->type == bfd_link_hash_defined
+         || p->h->type == bfd_link_hash_defweak)
+       continue;
+
+      /* For each set we build:
+          set:
+            .long number_of_elements
+            .long element0
+            ...
+            .long elementN
+            .long 0
+        except that we use the right size instead of .long.  When
+        generating relocatable output, we generate relocs instead of
+        addresses.  */
+      howto = bfd_reloc_type_lookup (link_info.output_bfd, p->reloc);
+      if (howto == NULL)
+       {
+         if (bfd_link_relocatable (&link_info))
+           {
+             einfo (_("%X%P: %s does not support reloc %s for set %s\n"),
+                    bfd_get_target (link_info.output_bfd),
+                    bfd_get_reloc_code_name (p->reloc),
+                    p->h->root.string);
+             continue;
+           }
 
-       /* If ld is invoked from collect, then the constructor list
-          will already have been defined, so don't do it again. */
+         /* If this is not a relocatable link, all we need is the
+            size, which we can get from the input BFD.  */
+         if (p->elements->section->owner != NULL)
+           howto = bfd_reloc_type_lookup (p->elements->section->owner,
+                                          p->reloc);
+         if (howto == NULL)
+           {
+             /* See PR 20911 for a reproducer.  */
+             if (p->elements->section->owner == NULL)
+               einfo (_("%X%P: special section %s does not support reloc %s for set %s\n"),
+                      bfd_section_name (p->elements->section),
+                      bfd_get_reloc_code_name (p->reloc),
+                      p->h->root.string);
+             else
+               einfo (_("%X%P: %s does not support reloc %s for set %s\n"),
+                      bfd_get_target (p->elements->section->owner),
+                      bfd_get_reloc_code_name (p->reloc),
+                      p->h->root.string);
+             continue;
+           }
+       }
+
+      reloc_size = bfd_get_reloc_size (howto);
+      switch (reloc_size)
+       {
+       case 1: size = BYTE; break;
+       case 2: size = SHORT; break;
+       case 4: size = LONG; break;
+       case 8:
+         if (howto->complain_on_overflow == complain_overflow_signed)
+           size = SQUAD;
+         else
+           size = QUAD;
+         break;
+       default:
+         einfo (_("%X%P: unsupported size %d for set %s\n"),
+                bfd_get_reloc_size (howto), p->h->root.string);
+         size = LONG;
+         break;
+       }
+
+      lang_add_assignment (exp_assign (".",
+                                      exp_unop (ALIGN_K,
+                                                exp_intop (reloc_size)),
+                                      FALSE));
+      lang_add_assignment (exp_assign (p->h->root.string,
+                                      exp_nameop (NAME, "."),
+                                      FALSE));
+      lang_add_data (size, exp_intop (p->count));
 
-       if (lookup->sdefs_chain == (asymbol **)NULL) 
+      for (e = p->elements; e != NULL; e = e->u.next)
+       {
+         if (config.map_file != NULL)
            {
-               size_t len = strlen(name);
-               char *end = ldmalloc(len+3);
-               strcpy(end, name);
-               strcat(end,"$e");
-
-               lang_add_assignment
-                   ( exp_assop('=',name, exp_nameop(NAME,".")));
-
-               lang_add_data
-                   (LONG, exp_binop('-',
-                                    exp_binop ( '/',
-                                               exp_binop ( '-',
-                                                          exp_nameop(NAME, end),
-                                                          exp_nameop(NAME,".")),
-                                               exp_intop(4)),
-
-                                    exp_intop(2)));
-
-                                     
-               lang_add_wild(name, (char *)NULL);
-               lang_add_data(LONG, exp_intop(0));
-               lang_add_assignment
-                   (exp_assop('=', end, exp_nameop(NAME,".")));
+             int len;
+
+             if (!header_printed)
+               {
+                 minfo (_("\nSet                 Symbol\n\n"));
+                 header_printed = TRUE;
+               }
+
+             minfo ("%s", p->h->root.string);
+             len = strlen (p->h->root.string);
+
+             if (len >= 19)
+               {
+                 print_nl ();
+                 len = 0;
+               }
+             while (len < 20)
+               {
+                 print_space ();
+                 ++len;
+               }
+
+             if (e->name != NULL)
+               minfo ("%pT\n", e->name);
+             else
+               minfo ("%G\n", e->section->owner, e->section, e->value);
            }
-       p = p->next;                
+
+         /* Need SEC_KEEP for --gc-sections.  */
+         if (!bfd_is_abs_section (e->section))
+           e->section->flags |= SEC_KEEP;
+
+         if (bfd_link_relocatable (&link_info))
+           lang_add_reloc (p->reloc, howto, e->section, e->name,
+                           exp_intop (e->value));
+         else
+           lang_add_data (size, exp_relop (e->section, e->value));
+       }
+
+      lang_add_data (size, exp_intop (0));
     }
-    stat_ptr = old;
-}
 
+  pop_stat_ptr ();
+}
This page took 0.027346 seconds and 4 git commands to generate.