]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - ld/emultempl/msp430.em
Update year range in copyright notice of binutils files
[thirdparty/binutils-gdb.git] / ld / emultempl / msp430.em
index 65e6fb23241eabd33565028a738a6bd213bc7d12..e3ea3c69a909b48b8b0bcbd76196da3e37b0b284 100644 (file)
@@ -4,7 +4,7 @@ fragment <<EOF
 /* This file is is generated by a shell script.  DO NOT EDIT! */
 
 /* Emulate the original gld for the given ${EMULATION_NAME}
-   Copyright (C) 2014-2017 Free Software Foundation, Inc.
+   Copyright (C) 2014-2021 Free Software Foundation, Inc.
    Written by Steve Chamberlain steve@cygnus.com
    Extended for the MSP430 by Nick Clifton  nickc@redhat.com
 
@@ -30,6 +30,7 @@ fragment <<EOF
 #include "sysdep.h"
 #include "bfd.h"
 #include "bfdlink.h"
+#include "ctf-api.h"
 
 #include "ld.h"
 #include "getopt.h"
@@ -215,6 +216,40 @@ scan_children (lang_statement_union_type * l)
   return amount;
 }
 
+#define WARN_UPPER 0
+#define WARN_LOWER 1
+#define WARN_TEXT 0
+#define WARN_DATA 1
+#define WARN_BSS 2
+#define WARN_RODATA 3
+
+/* Warn only once per output section.
+ * NAME starts with ".upper." or ".lower.".  */
+static void
+warn_no_output_section (const char *name)
+{
+  static bfd_boolean warned[2][4] = {{FALSE, FALSE, FALSE, FALSE},
+                                    {FALSE, FALSE, FALSE, FALSE}};
+  int i = WARN_LOWER;
+
+  if (strncmp (name, ".upper.", 7) == 0)
+    i = WARN_UPPER;
+
+  if (!warned[i][WARN_TEXT] && strcmp (name + 6, ".text") == 0)
+    warned[i][WARN_TEXT] = TRUE;
+  else if (!warned[i][WARN_DATA] && strcmp (name + 6, ".data") == 0)
+    warned[i][WARN_DATA] = TRUE;
+  else if (!warned[i][WARN_BSS] && strcmp (name + 6, ".bss") == 0)
+    warned[i][WARN_BSS] = TRUE;
+  else if (!warned[i][WARN_RODATA] && strcmp (name + 6, ".rodata") == 0)
+    warned[i][WARN_RODATA] = TRUE;
+  else
+    return;
+  einfo ("%P: warning: no input section rule matches %s in linker script\n",
+        name);
+}
+
+
 /* Place an orphan section.  We use this to put .either sections
    into either their lower or their upper equivalents.  */
 
@@ -226,7 +261,6 @@ gld${EMULATION_NAME}_place_orphan (asection * s,
   char * lower_name;
   char * upper_name;
   char * name;
-  char * buf = NULL;
   lang_output_section_statement_type * lower;
   lang_output_section_statement_type * upper;
 
@@ -240,6 +274,13 @@ gld${EMULATION_NAME}_place_orphan (asection * s,
   if (constraint != 0)
     return NULL;
 
+  if (strncmp (secname, ".upper.", 7) == 0
+      || strncmp (secname, ".lower.", 7) == 0)
+    {
+      warn_no_output_section (secname);
+      return NULL;
+    }
+
   /* We only need special handling for .either sections.  */
   if (strncmp (secname, ".either.", 8) != 0)
     return NULL;
@@ -252,7 +293,7 @@ gld${EMULATION_NAME}_place_orphan (asection * s,
      only use the part of the name before the second dot.  */
   if (strchr (secname + 1, '.') != NULL)
     {
-      buf = name = xstrdup (secname);
+      name = xstrdup (secname);
 
       * strchr (name + 1, '.') = 0;
     }
@@ -288,8 +329,6 @@ gld${EMULATION_NAME}_place_orphan (asection * s,
  end:
   free (upper_name);
   free (lower_name);
-  if (buf)
-    free (buf);
   return lower;
 }
 EOF
@@ -298,9 +337,10 @@ fi
 fragment <<EOF
 
 static bfd_boolean
-change_output_section (lang_statement_union_type ** head,
+change_output_section (lang_statement_union_type **head,
                       asection *s,
-                      lang_output_section_statement_type * new_output_section)
+                      lang_output_section_statement_type *new_os,
+                      lang_output_section_statement_type *old_os)
 {
   asection *is;
   lang_statement_union_type * prev = NULL;
@@ -315,20 +355,27 @@ change_output_section (lang_statement_union_type ** head,
          is = curr->input_section.section;
          if (is == s)
            {
+             lang_statement_list_type *old_list
+               = (lang_statement_list_type *) &old_os->children;
              s->output_section = NULL;
-             lang_add_section (& (new_output_section->children), s, NULL,
-                               new_output_section);
+             lang_add_section (&new_os->children, s, NULL, new_os);
+
              /* Remove the section from the old output section.  */
              if (prev == NULL)
                *head = curr->header.next;
              else
                prev->header.next = curr->header.next;
+             /* If the input section we just moved is the tail of the old
+                output section, then we also need to adjust that tail.  */
+             if (old_list->tail == (lang_statement_union_type **) curr)
+               old_list->tail = (lang_statement_union_type **) prev;
+
              return TRUE;
            }
          break;
        case lang_wild_statement_enum:
          if (change_output_section (&(curr->wild_statement.children.head),
-                                    s, new_output_section))
+                                    s, new_os, old_os))
            return TRUE;
          break;
        default:
@@ -341,51 +388,20 @@ change_output_section (lang_statement_union_type ** head,
 }
 
 static void
-move_prefixed_section (asection *s, char *new_name,
-                      lang_output_section_statement_type * new_output_sec)
-{
-  s->name = new_name;
-  if (s->output_section == NULL)
-    lang_add_section (& (new_output_sec->children), s, NULL, new_output_sec);
-  else
-    {
-      lang_output_section_statement_type * curr_output_sec
-       = lang_output_section_find (s->output_section->name);
-      change_output_section (&(curr_output_sec->children.head), s,
-                            new_output_sec);
-    }
-}
-
-static void
-add_region_prefix (bfd *abfd, asection *s,
-                  ATTRIBUTE_UNUSED void *unused)
+add_region_prefix (bfd *abfd ATTRIBUTE_UNUSED, asection *s,
+                  void *unused ATTRIBUTE_UNUSED)
 {
-  const char *curr_name = bfd_get_section_name (abfd, s);
-  char * base_name;
-  char * new_input_sec_name = NULL;
-  char * new_output_sec_name = NULL;
+  const char *curr_name = bfd_section_name (s);
   int region = REGION_NONE;
 
   if (strncmp (curr_name, ".text", 5) == 0)
-    {
-      region = code_region;
-      base_name = concat (".text", NULL);
-    }
+    region = code_region;
   else if (strncmp (curr_name, ".data", 5) == 0)
-    {
-      region = data_region;
-      base_name = concat (".data", NULL);
-    }
+    region = data_region;
   else if (strncmp (curr_name, ".bss", 4) == 0)
-    {
-      region = data_region;
-      base_name = concat (".bss", NULL);
-    }
+    region = data_region;
   else if (strncmp (curr_name, ".rodata", 7) == 0)
-    {
-      region = data_region;
-      base_name = concat (".rodata", NULL);
-    }
+    region = data_region;
   else
     return;
 
@@ -394,30 +410,10 @@ add_region_prefix (bfd *abfd, asection *s,
     case REGION_NONE:
       break;
     case REGION_UPPER:
-      new_input_sec_name = concat (".upper", curr_name, NULL);
-      new_output_sec_name = concat (".upper", base_name, NULL);
-      lang_output_section_statement_type * upper
-       = lang_output_section_find (new_output_sec_name);
-      if (upper != NULL)
-       {
-         move_prefixed_section (s, new_input_sec_name, upper);
-       }
-      else
-       einfo (_("%P: error: no section named %s in linker script\n"),
-              new_output_sec_name);
+      bfd_rename_section (s, concat (".upper", curr_name, NULL));
       break;
     case REGION_LOWER:
-      new_input_sec_name = concat (".lower", curr_name, NULL);
-      new_output_sec_name = concat (".lower", base_name, NULL);
-      lang_output_section_statement_type * lower
-       = lang_output_section_find (new_output_sec_name);
-      if (lower != NULL)
-       {
-         move_prefixed_section (s, new_input_sec_name, lower);
-       }
-      else
-       einfo (_("%P: error: no section named %s in linker script\n"),
-              new_output_sec_name);
+      bfd_rename_section (s, concat (".lower", curr_name, NULL));
       break;
     case REGION_EITHER:
       s->name = concat (".either", curr_name, NULL);
@@ -427,12 +423,6 @@ add_region_prefix (bfd *abfd, asection *s,
       FAIL ();
       break;
     }
-  free (base_name);
-  if (new_input_sec_name)
-    {
-      free (new_input_sec_name);
-      free (new_output_sec_name);
-    }
 }
 
 static void
@@ -482,15 +472,14 @@ gld${EMULATION_NAME}_add_options
 static void
 gld${EMULATION_NAME}_list_options (FILE * file)
 {
-  fprintf (file, _("\
-  --code-region={either,lower,upper,none}\n\
-  \tTransform .text* sections to {either,lower,upper,none}.text* sections.\n\
-  --data-region={either,lower,upper,none}\n\
-  \tTransform .data*, .rodata* and .bss* sections to\n\
-  {either,lower,upper,none}.{bss,data,rodata}* sections\n\
-  --disable-sec-transformation\n\
-  \tDisable transformation of .{text,data,bss,rodata}* sections to\n\
-  \tadd the {either,lower,upper,none} prefixes\n"));
+  fprintf (file, _("  --code-region={either,lower,upper,none}\n\
+        Transform .text* sections to {either,lower,upper,none}.text* sections\n"));
+  fprintf (file, _("  --data-region={either,lower,upper,none}\n\
+        Transform .data*, .rodata* and .bss* sections to\n\
+        {either,lower,upper,none}.{bss,data,rodata}* sections\n"));
+  fprintf (file, _("  --disable-sec-transformation\n\
+        Disable transformation of .{text,data,bss,rodata}* sections to\n\
+        add the {either,lower,upper,none} prefixes\n"));
 }
 
 static bfd_boolean
@@ -509,14 +498,14 @@ gld${EMULATION_NAME}_handle_option (int optc)
        code_region = REGION_NONE;
       else if (strlen (optarg) == 0)
        {
-         einfo (_("%P: --code-region requires an argument: \
-                  {upper,lower,either,none}\n"));
+         einfo (_("%P: --code-region requires an argument: "
+                  "{upper,lower,either,none}\n"));
          return FALSE;
        }
       else
        {
-         einfo (_("%P: error: unrecognized argument to --code-region= option: \
-                  \"%s\"\n"), optarg);
+         einfo (_("%P: error: unrecognized argument to --code-region= option: "
+                  "\"%s\"\n"), optarg);
          return FALSE;
        }
       break;
@@ -532,14 +521,14 @@ gld${EMULATION_NAME}_handle_option (int optc)
        data_region = REGION_NONE;
       else if (strlen (optarg) == 0)
        {
-         einfo (_("%P: --data-region requires an argument: \
-                  {upper,lower,either,none}\n"));
+         einfo (_("%P: --data-region requires an argument: "
+                  "{upper,lower,either,none}\n"));
          return FALSE;
        }
       else
        {
-         einfo (_("%P: error: unrecognized argument to --data-region= option: \
-                  \"%s\"\n"), optarg);
+         einfo (_("%P: error: unrecognized argument to --data-region= option: "
+                  "\"%s\"\n"), optarg);
          return FALSE;
        }
       break;
@@ -555,7 +544,8 @@ gld${EMULATION_NAME}_handle_option (int optc)
 }
 
 static void
-eval_upper_either_sections (bfd *abfd, asection *s, void *data)
+eval_upper_either_sections (bfd *abfd ATTRIBUTE_UNUSED,
+                           asection *s, void *data)
 {
   const char * base_sec_name;
   const char * curr_name;
@@ -577,7 +567,7 @@ eval_upper_either_sections (bfd *abfd, asection *s, void *data)
     return;
 
   base_sec_name = (const char *) data;
-  curr_name = bfd_get_section_name (abfd, s);
+  curr_name = bfd_section_name (s);
 
   /* Only concerned with .either input sections in the upper output section.  */
   either_name = concat (".either", base_sec_name, NULL);
@@ -622,11 +612,15 @@ eval_upper_either_sections (bfd *abfd, asection *s, void *data)
       upper_size = &upper_size_ram;
     }
 
-  /* Move sections in the upper region that would fit in the lower
-     region to the lower region.  */
-  if (*lower_size + s->size < lower->region->length)
+  /* If the upper region is overflowing, try moving sections to the lower
+     region.
+     Note that there isn't any general benefit to using lower memory over upper
+     memory, so we only move sections around with the goal of making the program
+     fit.  */
+  if (*upper_size > upper->region->length
+      && *lower_size + s->size < lower->region->length)
     {
-      if (change_output_section (&(upper->children.head), s, lower))
+      if (change_output_section (&(upper->children.head), s, lower, upper))
        {
          *upper_size -= s->size;
          *lower_size += s->size;
@@ -637,7 +631,8 @@ eval_upper_either_sections (bfd *abfd, asection *s, void *data)
 }
 
 static void
-eval_lower_either_sections (bfd *abfd, asection *s, void *data)
+eval_lower_either_sections (bfd *abfd ATTRIBUTE_UNUSED,
+                           asection *s, void *data)
 {
   const char * base_sec_name;
   const char * curr_name;
@@ -657,7 +652,7 @@ eval_lower_either_sections (bfd *abfd, asection *s, void *data)
     return;
 
   base_sec_name = (const char *) data;
-  curr_name = bfd_get_section_name (abfd, s);
+  curr_name = bfd_section_name (s);
 
   /* Only concerned with .either input sections in the lower or "default"
      output section i.e. not in the upper output section.  */
@@ -715,7 +710,7 @@ eval_lower_either_sections (bfd *abfd, asection *s, void *data)
     }
   /* Move sections that cause the lower region to overflow to the upper region.  */
   if (*lower_size + s->size > output_sec->region->length)
-    change_output_section (&(output_sec->children.head), s, upper);
+    change_output_section (&(output_sec->children.head), s, upper, output_sec);
   else
     *lower_size += s->size;
  end:
@@ -831,6 +826,85 @@ msp430_elf_after_allocation (void)
   gld${EMULATION_NAME}_after_allocation ();
 }
 
+/* Return TRUE if a non-debug input section in L has positive size and matches
+   the given name.  */
+static int
+input_section_exists (lang_statement_union_type * l, const char * name)
+{
+  while (l != NULL)
+    {
+      switch (l->header.type)
+       {
+       case lang_input_section_enum:
+         if ((l->input_section.section->flags & SEC_ALLOC)
+             && l->input_section.section->size > 0
+             && !strcmp (l->input_section.section->name, name))
+           return TRUE;
+         break;
+
+       case lang_wild_statement_enum:
+         if (input_section_exists (l->wild_statement.children.head, name))
+           return TRUE;
+         break;
+
+       default:
+         break;
+       }
+      l = l->header.next;
+    }
+  return FALSE;
+}
+
+/* Some MSP430 linker scripts do not include ALIGN directives to ensure
+   __preinit_array_start, __init_array_start or __fini_array_start are word
+   aligned.
+   If __*_array_start symbols are not word aligned, the code in crt0 to run
+   through the array and call the functions will crash.
+   To avoid warning unnecessarily when the .*_array sections are not being
+   used for running constructors/destructors, only emit the warning if
+   the associated section exists and has size.  */
+static void
+check_array_section_alignment (void)
+{
+  int i;
+  lang_output_section_statement_type * rodata_sec;
+  lang_output_section_statement_type * rodata2_sec;
+  const char * array_names[3][2] = { { ".init_array", "__init_array_start" },
+       { ".preinit_array", "__preinit_array_start" },
+       { ".fini_array", "__fini_array_start" } };
+
+  /* .{preinit,init,fini}_array could be in either .rodata or .rodata2.  */
+  rodata_sec = lang_output_section_find (".rodata");
+  rodata2_sec = lang_output_section_find (".rodata2");
+  if (rodata_sec == NULL && rodata2_sec == NULL)
+    return;
+
+  /* There are 3 .*_array sections which must be checked for alignment.  */
+  for (i = 0; i < 3; i++)
+    {
+      struct bfd_link_hash_entry * sym;
+      if (((rodata_sec && input_section_exists (rodata_sec->children.head,
+                                               array_names[i][0]))
+          || (rodata2_sec && input_section_exists (rodata2_sec->children.head,
+                                                   array_names[i][0])))
+         && (sym = bfd_link_hash_lookup (link_info.hash, array_names[i][1],
+                                         FALSE, FALSE, TRUE))
+         && sym->type == bfd_link_hash_defined
+         && sym->u.def.value % 2)
+       {
+         einfo ("%P: warning: \"%s\" symbol (%pU) is not word aligned\n",
+                array_names[i][1], NULL);
+       }
+    }
+}
+
+static void
+gld${EMULATION_NAME}_finish (void)
+{
+  finish_default ();
+  check_array_section_alignment ();
+}
+
 struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
 {
   ${LDEMUL_BEFORE_PARSE-gld${EMULATION_NAME}_before_parse},
@@ -839,6 +913,7 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
   ${LDEMUL_AFTER_PARSE-after_parse_default},
   msp430_elf_after_open,
   after_check_relocs_default,
+  before_place_orphans_default,
   msp430_elf_after_allocation,
   ${LDEMUL_SET_OUTPUT_ARCH-set_output_arch_default},
   ${LDEMUL_CHOOSE_TARGET-ldemul_default_target},
@@ -846,7 +921,7 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
   ${LDEMUL_GET_SCRIPT-gld${EMULATION_NAME}_get_script},
   "${EMULATION_NAME}",
   "${OUTPUT_FORMAT}",
-  ${LDEMUL_FINISH-finish_default},
+  gld${EMULATION_NAME}_finish,
   ${LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS-NULL},
   ${LDEMUL_OPEN_DYNAMIC_ARCHIVE-NULL},
   ${LDEMUL_PLACE_ORPHAN-gld${EMULATION_NAME}_place_orphan},
@@ -859,7 +934,11 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation =
   ${LDEMUL_RECOGNIZED_FILE-NULL},
   ${LDEMUL_FIND_POTENTIAL_LIBRARIES-NULL},
   ${LDEMUL_NEW_VERS_PATTERN-NULL},
-  ${LDEMUL_EXTRA_MAP_FILE_TEXT-NULL}
+  ${LDEMUL_EXTRA_MAP_FILE_TEXT-NULL},
+  ${LDEMUL_EMIT_CTF_EARLY-NULL},
+  ${LDEMUL_ACQUIRE_STRINGS_FOR_CTF-NULL},
+  ${LDEMUL_NEW_DYNSYM_FOR_CTF-NULL},
+  ${LDEMUL_PRINT_SYMBOL-NULL}
 };
 EOF
 # \f