Fix problems parsing RISCV architecture extenstions in the assembler.
[deliverable/binutils-gdb.git] / ld / ldlang.c
index eb4ba9eee467e6cbc21a5786c5faced538a1df52..726bc8e3846944a0e34d9b127e000a68a07ee0ad 100644 (file)
@@ -5878,97 +5878,173 @@ section_for_dot (void)
   return bfd_abs_section_ptr;
 }
 
-/* Fix any .startof., .sizeof., __start or __stop symbols.  When the
-   assemblers see the operator .startof. (section_name), it produces
-   an undefined symbol .startof.section_name.  Similarly, when it sees
-   .sizeof. (section_name), it produces an undefined symbol
-   .sizeof.section_name.  Also for ELF linker, __start_XXX or __stop_XXX
-   symbols should be resolved to the start and end of section XXX.  For
-   all the output sections, we look for such symbols, and set them to
-   the correct value.  */
+/* Array of __start/__stop/.startof./.sizeof/ symbols.  */
+
+static struct bfd_link_hash_entry **start_stop_syms;
+static size_t start_stop_count = 0;
+static size_t start_stop_alloc = 0;
+
+/* Give start/stop SYMBOL for SEC a preliminary definition, and add it
+   to start_stop_syms.  */
+
+static void
+lang_define_start_stop (const char *symbol, asection *sec)
+{
+  struct bfd_link_hash_entry *h;
+
+  h = bfd_define_start_stop (link_info.output_bfd, &link_info, symbol, sec);
+  if (h != NULL)
+    {
+      if (start_stop_count == start_stop_alloc)
+       {
+         start_stop_alloc = 2 * start_stop_alloc + 10;
+         start_stop_syms
+           = xrealloc (start_stop_syms,
+                       start_stop_alloc * sizeof (*start_stop_syms));
+       }
+      start_stop_syms[start_stop_count++] = h;
+    }
+}
+
+/* Check for input sections whose names match references to
+   __start_SECNAME or __stop_SECNAME symbols.  Give the symbols
+   preliminary definitions.  */
 
 static void
-lang_set_startof (void)
+lang_init_start_stop (void)
 {
+  bfd *abfd;
   asection *s;
-  char leading_char;
-  bfd_boolean is_elf;
-  bfd_boolean is_relocatable;
+  char leading_char = bfd_get_symbol_leading_char (link_info.output_bfd);
+
+  for (abfd = link_info.input_bfds; abfd != NULL; abfd = abfd->link.next)
+    for (s = abfd->sections; s != NULL; s = s->next)
+      {
+       const char *ps;
+       const char *secname = s->name;
+
+       for (ps = secname; *ps != '\0'; ps++)
+         if (!ISALNUM ((unsigned char) *ps) && *ps != '_')
+           break;
+       if (*ps == '\0')
+         {
+           char *symbol = (char *) xmalloc (10 + strlen (secname));
 
-  if (!config.build_constructors)
+           symbol[0] = leading_char;
+           sprintf (symbol + (leading_char != 0), "__start_%s", secname);
+           lang_define_start_stop (symbol, s);
+
+           symbol[1] = leading_char;
+           memcpy (symbol + 1 + (leading_char != 0), "__stop", 6);
+           lang_define_start_stop (symbol + 1, s);
+
+           free (symbol);
+         }
+      }
+}
+
+/* Iterate over start_stop_syms.  */
+
+static void
+foreach_start_stop (void (*func) (struct bfd_link_hash_entry *))
+{
+  size_t i;
+
+  for (i = 0; i < start_stop_count; ++i)
+    func (start_stop_syms[i]);
+}
+
+/* __start and __stop symbols are only supposed to be defined by the
+   linker for orphan sections, but we now extend that to sections that
+   map to an output section of the same name.  The symbols were
+   defined early for --gc-sections, before we mapped input to output
+   sections, so undo those that don't satisfy this rule.  */
+
+static void
+undef_start_stop (struct bfd_link_hash_entry *h)
+{
+  if (h->ldscript_def)
     return;
 
-  is_elf = (bfd_get_flavour (link_info.output_bfd)
-           == bfd_target_elf_flavour);
-  is_relocatable = bfd_link_relocatable (&link_info);
+  if (h->u.def.section->output_section == NULL
+      || h->u.def.section->output_section->owner != link_info.output_bfd
+      || strcmp (h->u.def.section->name,
+                h->u.def.section->output_section->name) != 0)
+    {
+      h->type = bfd_link_hash_undefined;
+      h->u.undef.abfd = NULL;
+    }
+}
+
+static void
+lang_undef_start_stop (void)
+{
+  foreach_start_stop (undef_start_stop);
+}
+
+/* Check for output sections whose names match references to
+   .startof.SECNAME or .sizeof.SECNAME symbols.  Give the symbols
+   preliminary definitions.  */
 
-  leading_char = bfd_get_symbol_leading_char (link_info.output_bfd);
+static void
+lang_init_startof_sizeof (void)
+{
+  asection *s;
 
   for (s = link_info.output_bfd->sections; s != NULL; s = s->next)
     {
-      const char *secname;
-      char *buf;
-      struct bfd_link_hash_entry *h;
+      const char *secname = s->name;
+      char *symbol = (char *) xmalloc (10 + strlen (secname));
 
-      secname = bfd_get_section_name (link_info.output_bfd, s);
-      buf = (char *) xmalloc (10 + strlen (secname));
+      sprintf (symbol, ".startof.%s", secname);
+      lang_define_start_stop (symbol, s);
 
-      if (!is_relocatable)
-       {
-         sprintf (buf, ".startof.%s", secname);
-         h = bfd_link_hash_lookup (link_info.hash, buf, FALSE, FALSE,
-                                   TRUE);
-         if (h != NULL && h->type == bfd_link_hash_undefined)
-           {
-             h->type = bfd_link_hash_defined;
-             h->u.def.value = 0;
-             h->u.def.section = s;
-           }
+      memcpy (symbol + 1, ".size", 5);
+      lang_define_start_stop (symbol + 1, s);
+      free (symbol);
+    }
+}
 
-         sprintf (buf, ".sizeof.%s", secname);
-         h = bfd_link_hash_lookup (link_info.hash, buf, FALSE, FALSE,
-                                   TRUE);
-         if (h != NULL && h->type == bfd_link_hash_undefined)
-           {
-             h->type = bfd_link_hash_defined;
-             h->u.def.value = TO_ADDR (s->size);
-             h->u.def.section = bfd_abs_section_ptr;
-           }
-       }
+/* Set .startof., .sizeof., __start and __stop symbols final values.  */
 
-      buf[0] = leading_char;
-      sprintf (buf + (buf[0] != 0), "__start_%s", secname);
-      h = bfd_link_hash_lookup (link_info.hash, buf, FALSE, FALSE,
-                               TRUE);
-      if (h != NULL
-         && (h->type == bfd_link_hash_undefined
-             || h->type == bfd_link_hash_undefweak))
+static void
+set_start_stop (struct bfd_link_hash_entry *h)
+{
+  if (h->ldscript_def
+      || h->type != bfd_link_hash_defined)
+    return;
+
+  if (h->root.string[0] == '.')
+    {
+      /* .startof. or .sizeof. symbol.
+        .startof. already has final value.  */
+      if (h->root.string[2] == 'i')
        {
-         h->type = bfd_link_hash_defined;
-         h->u.def.value = 0;
-         h->u.def.section = s;
-         if (is_elf)
-           ((struct elf_link_hash_entry *) h)->def_regular = 1;
+         /* .sizeof.  */
+         h->u.def.value = TO_ADDR (h->u.def.section->size);
+         h->u.def.section = bfd_abs_section_ptr;
        }
+    }
+  else
+    {
+      /* __start or __stop symbol.  */
+      int has_lead = bfd_get_symbol_leading_char (link_info.output_bfd) != 0;
 
-      buf[0] = leading_char;
-      sprintf (buf + (buf[0] != 0), "__stop_%s", secname);
-      h = bfd_link_hash_lookup (link_info.hash, buf, FALSE, FALSE,
-                               TRUE);
-      if (h != NULL
-         && (h->type == bfd_link_hash_undefined
-             || h->type == bfd_link_hash_undefweak))
+      h->u.def.section = h->u.def.section->output_section;
+      if (h->root.string[4 + has_lead] == 'o')
        {
-         h->type = bfd_link_hash_defined;
-         h->u.def.value = TO_ADDR (s->size);
-         h->u.def.section = s;
-         if (is_elf)
-           ((struct elf_link_hash_entry *) h)->def_regular = 1;
+         /* __stop_ */
+         h->u.def.value = TO_ADDR (h->u.def.section->size);
        }
-      free (buf);
     }
 }
 
+static void
+lang_finalize_start_stop (void)
+{
+  foreach_start_stop (set_start_stop);
+}
+
 static void
 lang_end (void)
 {
@@ -7035,6 +7111,12 @@ lang_process (void)
      files.  */
   ldctor_build_sets ();
 
+  /* Give initial values for __start and __stop symbols, so that  ELF
+     gc_sections will keep sections referenced by these symbols.  Must
+     be done before lang_do_assignments below.  */
+  if (config.build_constructors)
+    lang_init_start_stop ();
+
   /* PR 13683: We must rerun the assignments prior to running garbage
      collection in order to make sure that all symbol aliases are resolved.  */
   lang_do_assignments (lang_mark_phase_enum);
@@ -7089,6 +7171,17 @@ lang_process (void)
   /* Copy forward lma regions for output sections in same lma region.  */
   lang_propagate_lma_regions ();
 
+  /* Defining __start/__stop symbols early for --gc-sections to work
+     around a glibc build problem can result in these symbols being
+     defined when they should not be.  Fix them now.  */
+  if (config.build_constructors)
+    lang_undef_start_stop ();
+
+  /* Define .startof./.sizeof. symbols with preliminary values before
+     dynamic symbols are created.  */
+  if (!bfd_link_relocatable (&link_info))
+    lang_init_startof_sizeof ();
+
   /* Do anything special before sizing sections.  This is where ELF
      and other back-ends size dynamic sections.  */
   ldemul_before_allocation ();
@@ -7108,8 +7201,8 @@ lang_process (void)
      everything is.  This is where relaxation is done.  */
   ldemul_after_allocation ();
 
-  /* Fix any .startof. or .sizeof. symbols.  */
-  lang_set_startof ();
+  /* Fix any __start, __stop, .startof. or .sizeof. symbols.  */
+  lang_finalize_start_stop ();
 
   /* Do all the assignments, now that we know the final resting places
      of all the symbols.  */
This page took 0.043317 seconds and 4 git commands to generate.