ELF: Group and sort output note sections by section alignments
[deliverable/binutils-gdb.git] / ld / ldlang.c
index 2cb16476924b90241e87707d66d247306e75ffb2..1a277871932c1870c9474508284c8a04bc9db7c3 100644 (file)
@@ -1,5 +1,5 @@
 /* Linker command language support.
-   Copyright (C) 1991-2017 Free Software Foundation, Inc.
+   Copyright (C) 1991-2018 Free Software Foundation, Inc.
 
    This file is part of the GNU Binutils.
 
@@ -1199,8 +1199,8 @@ output_section_statement_newfunc (struct bfd_hash_entry *entry,
   ret = (struct out_section_hash_entry *) entry;
   memset (&ret->s, 0, sizeof (ret->s));
   ret->s.header.type = lang_output_section_statement_enum;
-  ret->s.output_section_statement.subsection_alignment = -1;
-  ret->s.output_section_statement.section_alignment = -1;
+  ret->s.output_section_statement.subsection_alignment = NULL;
+  ret->s.output_section_statement.section_alignment = NULL;
   ret->s.output_section_statement.block_value = 1;
   lang_list_init (&ret->s.output_section_statement.children);
   lang_statement_append (stat_ptr, &ret->s, &ret->s.header.next);
@@ -1231,7 +1231,7 @@ output_section_statement_table_init (void)
                              output_section_statement_newfunc,
                              sizeof (struct out_section_hash_entry),
                              61))
-    einfo (_("%P%F: can not create hash table: %E\n"));
+    einfo (_("%F%P: can not create hash table: %E\n"));
 }
 
 static void
@@ -1315,13 +1315,13 @@ lang_memory_region_lookup (const char *const name, bfd_boolean create)
       if (strcmp (n->name, name) == 0)
        {
          if (create)
-           einfo (_("%P:%S: warning: redeclaration of memory region `%s'\n"),
+           einfo (_("%P:%pS: warning: redeclaration of memory region `%s'\n"),
                   NULL, name);
          return r;
        }
 
   if (!create && strcmp (name, DEFAULT_MEMORY_REGION))
-    einfo (_("%P:%S: warning: memory region `%s' not declared\n"),
+    einfo (_("%P:%pS: warning: memory region `%s' not declared\n"),
           NULL, name);
 
   new_region = (lang_memory_region_type *)
@@ -1358,7 +1358,7 @@ lang_memory_region_alias (const char *alias, const char *region_name)
      the default memory region.  */
   if (strcmp (region_name, DEFAULT_MEMORY_REGION) == 0
       || strcmp (alias, DEFAULT_MEMORY_REGION) == 0)
-    einfo (_("%F%P:%S: error: alias for default memory region\n"), NULL);
+    einfo (_("%F%P:%pS: error: alias for default memory region\n"), NULL);
 
   /* Look for the target region and check if the alias is not already
      in use.  */
@@ -1369,14 +1369,14 @@ lang_memory_region_alias (const char *alias, const char *region_name)
        if (region == NULL && strcmp (n->name, region_name) == 0)
          region = r;
        if (strcmp (n->name, alias) == 0)
-         einfo (_("%F%P:%S: error: redefinition of memory region "
+         einfo (_("%F%P:%pS: error: redefinition of memory region "
                   "alias `%s'\n"),
                 NULL, alias);
       }
 
   /* Check if the target region exists.  */
   if (region == NULL)
-    einfo (_("%F%P:%S: error: memory region `%s' "
+    einfo (_("%F%P:%pS: error: memory region `%s' "
             "for alias `%s' does not exist\n"),
           NULL, region_name, alias);
 
@@ -1435,7 +1435,7 @@ lang_output_section_statement_lookup (const char *name,
   if (entry == NULL)
     {
       if (create)
-       einfo (_("%P%F: failed creating section `%s': %E\n"), name);
+       einfo (_("%F%P: failed creating section `%s': %E\n"), name);
       return NULL;
     }
 
@@ -1474,7 +1474,7 @@ lang_output_section_statement_lookup (const char *name,
                                             name));
       if (entry == NULL)
        {
-         einfo (_("%P%F: failed creating section `%s': %E\n"), name);
+         einfo (_("%F%P: failed creating section `%s': %E\n"), name);
          return NULL;
        }
       entry->root = last_ent->root;
@@ -1875,6 +1875,7 @@ lang_insert_orphan (asection *s,
   if (after != NULL && os->bfd_section != NULL)
     {
       asection *snew, *as;
+      bfd_boolean place_after = place->stmt == NULL;
 
       snew = os->bfd_section;
 
@@ -1912,6 +1913,142 @@ lang_insert_orphan (asection *s,
          /* Now tack it back on in the right place.  */
          bfd_section_list_append (link_info.output_bfd, snew);
        }
+      else if ((bfd_get_flavour (link_info.output_bfd)
+               == bfd_target_elf_flavour)
+              && (bfd_get_flavour (s->owner)
+                  == bfd_target_elf_flavour)
+              && ((elf_section_type (s) == SHT_NOTE
+                   && (s->flags & SEC_LOAD) != 0)
+                  || (elf_section_type (as) == SHT_NOTE
+                      && (as->flags & SEC_LOAD) != 0)))
+       {
+         /* Make sure that output note sections are grouped and sorted
+            by alignments when inserting a note section or insert a
+            section after a note section,  */
+         asection *sec;
+         /* A specific section after which the output note section
+            should be placed.  */
+         asection *after_sec;
+         /* True if we need to insert the orphan section after a
+            specific section to maintain output note section order.  */
+         bfd_boolean after_sec_note;
+
+         /* Group and sort output note section by alignments in
+            ascending order.  */
+         after_sec = NULL;
+         if (elf_section_type (s) == SHT_NOTE
+             && (s->flags & SEC_LOAD) != 0)
+           {
+             /* Search forward for the last output note section
+                with equal or larger alignments.  */
+             asection *first_note = NULL;
+
+             for (sec = as;
+                  (sec != NULL
+                   && !bfd_is_abs_section (sec));
+                  sec = sec->next)
+               if (sec != snew
+                   && elf_section_type (sec) == SHT_NOTE
+                   && (sec->flags & SEC_LOAD) != 0)
+                 {
+                   if (!first_note)
+                     first_note = sec;
+                   if (sec->alignment_power >= s->alignment_power)
+                     after_sec = sec;
+                 }
+
+             if (after_sec)
+               after_sec_note = TRUE;
+             else
+               {
+                 /* Search backward for the first output note section
+                    as well as the last output note section with equal
+                    or larger alignments.  */
+                 after_sec = NULL;
+                 for (sec = as;
+                      (sec != NULL
+                       && !bfd_is_abs_section (sec));
+                      sec = sec->prev)
+                   if (sec != snew
+                       && elf_section_type (sec) == SHT_NOTE
+                       && (sec->flags & SEC_LOAD) != 0)
+                     {
+                       first_note = sec;
+                       if (!after_sec
+                           && sec->alignment_power >= s->alignment_power)
+                         after_sec = sec;
+                     }
+
+                 /* If this will be the first note section, it can be
+                    placed at the default location.  */
+                 after_sec_note = first_note != NULL;
+                 if (after_sec == NULL && after_sec_note)
+                   {
+                     /* If all output note sections have smaller
+                        alignments, place the section before all
+                        output note sections.  AFTER_SEC will be
+                        NULL if FIRST_NOTE is the first output
+                        section.  */
+                     after_sec = first_note->prev;
+                   }
+               }
+           }
+         else
+           {
+             /* Don't place non-note sections in the middle of note
+                sections.  */
+             after_sec_note = TRUE;
+             after_sec = as;
+             for (sec = as->next;
+                  (sec != NULL
+                   && !bfd_is_abs_section (sec));
+                  sec = sec->next)
+               if (elf_section_type (sec) == SHT_NOTE
+                   && (sec->flags & SEC_LOAD) != 0)
+                 after_sec = sec;
+           }
+
+         if (after_sec_note)
+           {
+             if (after_sec)
+               {
+                 /* Insert OS after AFTER_SEC output statement.  */
+                 lang_output_section_statement_type *stmt;
+                 for (stmt = after;
+                      stmt != NULL;
+                      stmt = stmt->next)
+                   if (stmt->bfd_section == after_sec)
+                     {
+                       place_after = TRUE;
+                       after = stmt;
+                       break;
+                     }
+               }
+
+             if (after_sec == NULL || after_sec->next != snew)
+               {
+                 /* Unlink the section.  */
+                 bfd_section_list_remove (link_info.output_bfd, snew);
+
+                 /* Place SNEW after AFTER_SEC.  If AFTER_SEC is NULL,
+                    prepend SNEW.  */
+                 if (after_sec)
+                   bfd_section_list_insert_after (link_info.output_bfd,
+                                                  after_sec, snew);
+                 else
+                   bfd_section_list_prepend (link_info.output_bfd, snew);
+               }
+           }
+         else if (as != snew && as->prev != snew)
+           {
+             /* Unlink the section.  */
+             bfd_section_list_remove (link_info.output_bfd, snew);
+
+             /* Now tack it back on in the right place.  */
+             bfd_section_list_insert_before (link_info.output_bfd,
+                                             as, snew);
+           }
+       }
       else if (as != snew && as->prev != snew)
        {
          /* Unlink the section.  */
@@ -1938,7 +2075,8 @@ lang_insert_orphan (asection *s,
        {
          lang_output_section_statement_type *newly_added_os;
 
-         if (place->stmt == NULL)
+         /* Place OS after AFTER if AFTER_NOTE is TRUE.  */
+         if (place_after)
            {
              lang_statement_union_type **where = insert_os_after (after);
 
@@ -2016,8 +2154,8 @@ lang_print_asneeded (void)
        }
 
       if (m->ref != NULL)
-       minfo ("%B ", m->ref);
-      minfo ("(%T)\n", m->name);
+       minfo ("%pB ", m->ref);
+      minfo ("(%pT)\n", m->name);
     }
 }
 
@@ -2164,7 +2302,7 @@ static void
 init_os (lang_output_section_statement_type *s, flagword flags)
 {
   if (strcmp (s->name, DISCARD_SECTION_NAME) == 0)
-    einfo (_("%P%F: Illegal use of `%s' section\n"), DISCARD_SECTION_NAME);
+    einfo (_("%F%P: illegal use of `%s' section\n"), DISCARD_SECTION_NAME);
 
   if (s->constraint != SPECIAL)
     s->bfd_section = bfd_get_section_by_name (link_info.output_bfd, s->name);
@@ -2173,7 +2311,7 @@ init_os (lang_output_section_statement_type *s, flagword flags)
                                                         s->name, flags);
   if (s->bfd_section == NULL)
     {
-      einfo (_("%P%F: output format %s cannot represent section"
+      einfo (_("%F%P: output format %s cannot represent section"
               " called %s: %E\n"),
             link_info.output_bfd->xvec->name, s->name);
     }
@@ -2193,8 +2331,9 @@ init_os (lang_output_section_statement_type *s, flagword flags)
     exp_init_os (s->load_base);
 
   /* If supplied an alignment, set it.  */
-  if (s->section_alignment != -1)
-    s->bfd_section->alignment_power = s->section_alignment;
+  if (s->section_alignment != NULL)
+    s->bfd_section->alignment_power = exp_get_power (s->section_alignment,
+                                                    "section alignment");
 }
 
 /* Make sure that all output sections mentioned in an expression are
@@ -2207,6 +2346,7 @@ exp_init_os (etree_type *exp)
     {
     case etree_assign:
     case etree_provide:
+    case etree_provided:
       exp_init_os (exp->assign.src);
       break;
 
@@ -2769,15 +2909,15 @@ load_symbols (lang_input_statement_type *entry,
        {
          char **p;
 
-         einfo (_("%B: file not recognized: %E\n"), entry->the_bfd);
-         einfo (_("%B: matching formats:"), entry->the_bfd);
+         einfo (_("%P: %pB: file not recognized: %E;"
+                  " matching formats:"), entry->the_bfd);
          for (p = matching; *p != NULL; p++)
            einfo (" %s", *p);
          einfo ("%F\n");
        }
       else if (err != bfd_error_file_not_recognized
               || place == NULL)
-       einfo (_("%F%B: file not recognized: %E\n"), entry->the_bfd);
+       einfo (_("%F%P: %pB: file not recognized: %E\n"), entry->the_bfd);
 
       bfd_close (entry->the_bfd);
       entry->the_bfd = NULL;
@@ -2828,7 +2968,7 @@ load_symbols (lang_input_statement_type *entry,
       if (!entry->flags.reload)
        ldlang_add_file (entry);
       if (trace_files || verbose)
-       info_msg ("%I\n", entry);
+       info_msg ("%pI\n", entry);
       break;
 
     case bfd_archive:
@@ -2850,7 +2990,7 @@ load_symbols (lang_input_statement_type *entry,
 
              if (!bfd_check_format (member, bfd_object))
                {
-                 einfo (_("%F%B: member %B in archive is not an object\n"),
+                 einfo (_("%F%P: %pB: member %pB in archive is not an object\n"),
                         entry->the_bfd, member);
                  loaded = FALSE;
                }
@@ -2865,7 +3005,7 @@ load_symbols (lang_input_statement_type *entry,
                 substitute BFD for us.  */
              if (!bfd_link_add_symbols (subsbfd, &link_info))
                {
-                 einfo (_("%F%B: error adding symbols: %E\n"), member);
+                 einfo (_("%F%P: %pB: error adding symbols: %E\n"), member);
                  loaded = FALSE;
                }
            }
@@ -2879,7 +3019,7 @@ load_symbols (lang_input_statement_type *entry,
   if (bfd_link_add_symbols (entry->the_bfd, &link_info))
     entry->flags.loaded = TRUE;
   else
-    einfo (_("%F%B: error adding symbols: %E\n"), entry->the_bfd);
+    einfo (_("%F%P: %pB: error adding symbols: %E\n"), entry->the_bfd);
 
   return entry->flags.loaded;
 }
@@ -3167,23 +3307,23 @@ open_output (const char *name)
   if (link_info.output_bfd == NULL)
     {
       if (bfd_get_error () == bfd_error_invalid_target)
-       einfo (_("%P%F: target %s not found\n"), output_target);
+       einfo (_("%F%P: target %s not found\n"), output_target);
 
-      einfo (_("%P%F: cannot open output file %s: %E\n"), name);
+      einfo (_("%F%P: cannot open output file %s: %E\n"), name);
     }
 
   delete_output_file_on_failure = TRUE;
 
   if (!bfd_set_format (link_info.output_bfd, bfd_object))
-    einfo (_("%P%F:%s: can not make object file: %E\n"), name);
+    einfo (_("%F%P: %s: can not make object file: %E\n"), name);
   if (!bfd_set_arch_mach (link_info.output_bfd,
                           ldfile_output_architecture,
                           ldfile_output_machine))
-    einfo (_("%P%F:%s: can not set architecture: %E\n"), name);
+    einfo (_("%F%P: %s: can not set architecture: %E\n"), name);
 
   link_info.hash = bfd_link_hash_table_create (link_info.output_bfd);
   if (link_info.hash == NULL)
-    einfo (_("%P%F: can not create hash table: %E\n"));
+    einfo (_("%F%P: can not create hash table: %E\n"));
 
   bfd_set_gp_size (link_info.output_bfd, g_switch_value);
 }
@@ -3359,9 +3499,7 @@ open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode)
 #endif
          break;
        case lang_assignment_statement_enum:
-         if (s->assignment_statement.exp->type.node_class != etree_assert
-             && s->assignment_statement.exp->assign.defsym)
-           /* This is from a --defsym on the command line.  */
+         if (s->assignment_statement.exp->type.node_class != etree_assert)
            exp_fold_tree_no_dot (s->assignment_statement.exp);
          break;
        default:
@@ -3409,11 +3547,12 @@ insert_undefined (const char *name)
 
   h = bfd_link_hash_lookup (link_info.hash, name, TRUE, FALSE, TRUE);
   if (h == NULL)
-    einfo (_("%P%F: bfd_link_hash_lookup failed: %E\n"));
+    einfo (_("%F%P: bfd_link_hash_lookup failed: %E\n"));
   if (h->type == bfd_link_hash_new)
     {
       h->type = bfd_link_hash_undefined;
       h->u.undef.abfd = NULL;
+      h->non_ir_ref_regular = TRUE;
       if (is_elf_hash_table (link_info.hash))
        ((struct elf_link_hash_entry *) h)->mark = 1;
       bfd_link_add_undef (link_info.hash, h);
@@ -3478,7 +3617,7 @@ ldlang_check_require_defined_symbols (void)
       if (h == NULL
          || (h->type != bfd_link_hash_defined
              && h->type != bfd_link_hash_defweak))
-       einfo(_("%P%X: required symbol `%s' not defined\n"), ptr->name);
+       einfo(_("%X%P: required symbol `%s' not defined\n"), ptr->name);
     }
 }
 
@@ -3946,9 +4085,7 @@ strip_excluded_output_sections (void)
 }
 
 /* Called from ldwrite to clear out asection.map_head and
-   asection.map_tail for use as link_orders in ldwrite.
-   FIXME: Except for sh64elf.em which starts creating link_orders in
-   its after_allocation routine so needs to call it early.  */
+   asection.map_tail for use as link_orders in ldwrite.  */
 
 void
 lang_clear_os_map (void)
@@ -4143,7 +4280,7 @@ print_one_symbol (struct bfd_link_hash_entry *hash_entry, void *ptr)
              + hash_entry->u.def.section->output_offset
              + hash_entry->u.def.section->output_section->vma));
 
-      minfo ("             %T\n", hash_entry->root.string);
+      minfo ("             %pT\n", hash_entry->root.string);
     }
 
   return TRUE;
@@ -4231,7 +4368,7 @@ print_input_section (asection *i, bfd_boolean is_discarded)
        size = 0;
     }
 
-  minfo ("0x%V %W %B\n", addr, size, i->owner);
+  minfo ("0x%V %W %pB\n", addr, size, i->owner);
 
   if (size != i->rawsize && i->rawsize != 0)
     {
@@ -4676,8 +4813,9 @@ insert_pad (lang_statement_union_type **ptr,
     }
   pad->padding_statement.output_offset = dot - output_section->vma;
   pad->padding_statement.size = alignment_needed;
-  output_section->size = TO_SIZE (dot + TO_ADDR (alignment_needed)
-                                 - output_section->vma);
+  if (!(output_section->flags & SEC_FIXED_SIZE))
+    output_section->size = TO_SIZE (dot + TO_ADDR (alignment_needed)
+                                   - output_section->vma);
 }
 
 /* Work out how much this section will move the dot point.  */
@@ -4707,8 +4845,10 @@ size_input_section
         is greater than any seen before, then record it too.  Perform
         the alignment by inserting a magic 'padding' statement.  */
 
-      if (output_section_statement->subsection_alignment != -1)
-       i->alignment_power = output_section_statement->subsection_alignment;
+      if (output_section_statement->subsection_alignment != NULL)
+       i->alignment_power
+         = exp_get_power (output_section_statement->subsection_alignment,
+                          "subsection alignment");
 
       if (o->alignment_power < i->alignment_power)
        o->alignment_power = i->alignment_power;
@@ -4726,7 +4866,8 @@ size_input_section
 
       /* Mark how big the output section must be to contain this now.  */
       dot += TO_ADDR (i->size);
-      o->size = TO_SIZE (dot - o->vma);
+      if (!(o->flags & SEC_FIXED_SIZE))
+       o->size = TO_SIZE (dot - o->vma);
     }
 
   return dot;
@@ -4956,7 +5097,7 @@ os_region_check (lang_output_section_statement_type *os,
     {
       if (tree != NULL)
        {
-         einfo (_("%X%P: address 0x%v of %B section `%s'"
+         einfo (_("%X%P: address 0x%v of %pB section `%s'"
                   " is not within region `%s'\n"),
                 region->current,
                 os->bfd_section->owner,
@@ -4967,7 +5108,7 @@ os_region_check (lang_output_section_statement_type *os,
        {
          region->had_full_message = TRUE;
 
-         einfo (_("%X%P: %B section `%s' will not fit in region `%s'\n"),
+         einfo (_("%X%P: %pB section `%s' will not fit in region `%s'\n"),
                 os->bfd_section->owner,
                 os->bfd_section->name,
                 region->name_list.name);
@@ -4975,6 +5116,30 @@ os_region_check (lang_output_section_statement_type *os,
     }
 }
 
+static void
+ldlang_check_relro_region (lang_statement_union_type *s,
+                          seg_align_type *seg)
+{
+  if (seg->relro == exp_seg_relro_start)
+    {
+      if (!seg->relro_start_stat)
+       seg->relro_start_stat = s;
+      else
+       {
+         ASSERT (seg->relro_start_stat == s);
+       }
+    }
+  else if (seg->relro == exp_seg_relro_end)
+    {
+      if (!seg->relro_end_stat)
+       seg->relro_end_stat = s;
+      else
+       {
+         ASSERT (seg->relro_end_stat == s);
+       }
+    }
+}
+
 /* Set the sizes for all the output sections.  */
 
 static bfd_vma
@@ -5024,7 +5189,7 @@ lang_size_sections_1
                      dot += expld.result.section->vma;
                  }
                else if (expld.phase != lang_mark_phase_enum)
-                 einfo (_("%F%S: non constant or forward reference"
+                 einfo (_("%F%P:%pS: non constant or forward reference"
                           " address expression for section %s\n"),
                         os->addr_tree, os->name);
              }
@@ -5049,14 +5214,15 @@ lang_size_sections_1
                    || os->children.head->header.next != NULL
                    || (os->children.head->header.type
                        != lang_input_section_enum))
-                 einfo (_("%P%X: Internal error on COFF shared library"
+                 einfo (_("%X%P: internal error on COFF shared library"
                           " section %s\n"), os->name);
 
                input = os->children.head->input_section.section;
                bfd_set_section_vma (os->bfd_section->owner,
                                     os->bfd_section,
                                     bfd_section_vma (input->owner, input));
-               os->bfd_section->size = input->size;
+               if (!(os->bfd_section->flags & SEC_FIXED_SIZE))
+                 os->bfd_section->size = input->size;
                break;
              }
 
@@ -5107,7 +5273,7 @@ lang_size_sections_1
                           overridden by the using the --no-check-sections
                           switch.  */
                        if (command_line.check_section_addresses)
-                         einfo (_("%P%F: error: no memory region specified"
+                         einfo (_("%F%P: error: no memory region specified"
                                   " for loadable section `%s'\n"),
                                 bfd_get_section_name (link_info.output_bfd,
                                                       os->bfd_section));
@@ -5122,7 +5288,8 @@ lang_size_sections_1
                    section_alignment = os->bfd_section->alignment_power;
                  }
                else
-                 section_alignment = os->section_alignment;
+                 section_alignment = exp_get_power (os->section_alignment,
+                                                    "section alignment");
 
                /* Align to what the section needs.  */
                if (section_alignment > 0)
@@ -5171,7 +5338,9 @@ lang_size_sections_1
                          + os->block_value - 1)
                         & - (bfd_vma) os->block_value);
 
-               os->bfd_section->size = TO_SIZE (after - os->bfd_section->vma);
+               if (!(os->bfd_section->flags & SEC_FIXED_SIZE))
+                 os->bfd_section->size = TO_SIZE (after
+                                                  - os->bfd_section->vma);
              }
 
            /* Set section lma.  */
@@ -5198,7 +5367,8 @@ lang_size_sections_1
                       only align according to the value in the output
                       statement.  */
                    if (os->lma_region != os->region)
-                     section_alignment = os->section_alignment;
+                     section_alignment = exp_get_power (os->section_alignment,
+                                                        "section alignment");
                    if (section_alignment > 0)
                      lma = align_power (lma, section_alignment);
                  }
@@ -5356,8 +5526,10 @@ lang_size_sections_1
            if (size < TO_SIZE ((unsigned) 1))
              size = TO_SIZE ((unsigned) 1);
            dot += TO_ADDR (size);
-           output_section_statement->bfd_section->size
-             = TO_SIZE (dot - output_section_statement->bfd_section->vma);
+           if (!(output_section_statement->bfd_section->flags
+                 & SEC_FIXED_SIZE))
+             output_section_statement->bfd_section->size
+               = TO_SIZE (dot - output_section_statement->bfd_section->vma);
 
          }
          break;
@@ -5372,8 +5544,10 @@ lang_size_sections_1
              output_section_statement->bfd_section;
            size = bfd_get_reloc_size (s->reloc_statement.howto);
            dot += TO_ADDR (size);
-           output_section_statement->bfd_section->size
-             = TO_SIZE (dot - output_section_statement->bfd_section->vma);
+           if (!(output_section_statement->bfd_section->flags
+                 & SEC_FIXED_SIZE))
+             output_section_statement->bfd_section->size
+               = TO_SIZE (dot - output_section_statement->bfd_section->vma);
          }
          break;
 
@@ -5402,7 +5576,7 @@ lang_size_sections_1
                bfd_boolean again;
 
                if (!bfd_relax_section (i->owner, i, &link_info, &again))
-                 einfo (_("%P%F: can't relax section: %E\n"));
+                 einfo (_("%F%P: can't relax section: %E\n"));
                if (again)
                  *relax = TRUE;
              }
@@ -5432,24 +5606,8 @@ lang_size_sections_1
                           output_section_statement->bfd_section,
                           &newdot);
 
-           if (expld.dataseg.relro == exp_seg_relro_start)
-             {
-               if (!expld.dataseg.relro_start_stat)
-                 expld.dataseg.relro_start_stat = s;
-               else
-                 {
-                   ASSERT (expld.dataseg.relro_start_stat == s);
-                 }
-             }
-           else if (expld.dataseg.relro == exp_seg_relro_end)
-             {
-               if (!expld.dataseg.relro_end_stat)
-                 expld.dataseg.relro_end_stat = s;
-               else
-                 {
-                   ASSERT (expld.dataseg.relro_end_stat == s);
-                 }
-             }
+           ldlang_check_relro_region (s, &expld.dataseg);
+
            expld.dataseg.relro = exp_seg_relro_none;
 
            /* This symbol may be relative to this section.  */
@@ -5589,90 +5747,136 @@ one_lang_size_sections_pass (bfd_boolean *relax, bfd_boolean check_regions)
                        0, 0, relax, check_regions);
 }
 
-void
-lang_size_sections (bfd_boolean *relax, bfd_boolean check_regions)
+static bfd_boolean
+lang_size_segment (seg_align_type *seg)
 {
-  expld.phase = lang_allocating_phase_enum;
-  expld.dataseg.phase = exp_seg_none;
+  /* If XXX_SEGMENT_ALIGN XXX_SEGMENT_END pair was seen, check whether
+     a page could be saved in the data segment.  */
+  bfd_vma first, last;
 
-  one_lang_size_sections_pass (relax, check_regions);
-  if (expld.dataseg.phase == exp_seg_end_seen
-      && link_info.relro && expld.dataseg.relro_end)
+  first = -seg->base & (seg->pagesize - 1);
+  last = seg->end & (seg->pagesize - 1);
+  if (first && last
+      && ((seg->base & ~(seg->pagesize - 1))
+         != (seg->end & ~(seg->pagesize - 1)))
+      && first + last <= seg->pagesize)
     {
-      bfd_vma initial_base, relro_end, desired_end;
-      asection *sec;
+      seg->phase = exp_seg_adjust;
+      return TRUE;
+    }
 
-      /* Compute the expected PT_GNU_RELRO segment end.  */
-      relro_end = ((expld.dataseg.relro_end + expld.dataseg.pagesize - 1)
-                  & ~(expld.dataseg.pagesize - 1));
+  seg->phase = exp_seg_done;
+  return FALSE;
+}
 
-      /* Adjust by the offset arg of DATA_SEGMENT_RELRO_END.  */
-      desired_end = relro_end - expld.dataseg.relro_offset;
+static bfd_vma
+lang_size_relro_segment_1 (seg_align_type *seg)
+{
+  bfd_vma relro_end, desired_end;
+  asection *sec;
 
-      /* For sections in the relro segment..  */
-      for (sec = link_info.output_bfd->section_last; sec; sec = sec->prev)
-       if ((sec->flags & SEC_ALLOC) != 0
-           && sec->vma >= expld.dataseg.base
-           && sec->vma < expld.dataseg.relro_end - expld.dataseg.relro_offset)
-         {
-           /* Where do we want to put this section so that it ends as
-              desired?  */
-           bfd_vma start, end, bump;
-
-           end = start = sec->vma;
-           if (!IS_TBSS (sec))
-             end += TO_ADDR (sec->size);
-           bump = desired_end - end;
-           /* We'd like to increase START by BUMP, but we must heed
-              alignment so the increase might be less than optimum.  */
-           start += bump;
-           start &= ~(((bfd_vma) 1 << sec->alignment_power) - 1);
-           /* This is now the desired end for the previous section.  */
-           desired_end = start;
-         }
+  /* Compute the expected PT_GNU_RELRO/PT_LOAD segment end.  */
+  relro_end = ((seg->relro_end + seg->pagesize - 1)
+              & ~(seg->pagesize - 1));
+
+  /* Adjust by the offset arg of XXX_SEGMENT_RELRO_END.  */
+  desired_end = relro_end - seg->relro_offset;
+
+  /* For sections in the relro segment..  */
+  for (sec = link_info.output_bfd->section_last; sec; sec = sec->prev)
+    if ((sec->flags & SEC_ALLOC) != 0
+       && sec->vma >= seg->base
+       && sec->vma < seg->relro_end - seg->relro_offset)
+      {
+       /* Where do we want to put this section so that it ends as
+          desired?  */
+       bfd_vma start, end, bump;
+
+       end = start = sec->vma;
+       if (!IS_TBSS (sec))
+         end += TO_ADDR (sec->size);
+       bump = desired_end - end;
+       /* We'd like to increase START by BUMP, but we must heed
+          alignment so the increase might be less than optimum.  */
+       start += bump;
+       start &= ~(((bfd_vma) 1 << sec->alignment_power) - 1);
+       /* This is now the desired end for the previous section.  */
+       desired_end = start;
+      }
+
+  seg->phase = exp_seg_relro_adjust;
+  ASSERT (desired_end >= seg->base);
+  seg->base = desired_end;
+  return relro_end;
+}
 
-      expld.dataseg.phase = exp_seg_relro_adjust;
-      ASSERT (desired_end >= expld.dataseg.base);
-      initial_base = expld.dataseg.base;
-      expld.dataseg.base = desired_end;
+static bfd_boolean
+lang_size_relro_segment (bfd_boolean *relax, bfd_boolean check_regions)
+{
+  bfd_boolean do_reset = FALSE;
+  bfd_boolean do_data_relro;
+  bfd_vma data_initial_base, data_relro_end;
+
+  if (link_info.relro && expld.dataseg.relro_end)
+    {
+      do_data_relro = TRUE;
+      data_initial_base = expld.dataseg.base;
+      data_relro_end = lang_size_relro_segment_1 (&expld.dataseg);
+    }
+  else
+    {
+      do_data_relro = FALSE;
+      data_initial_base = data_relro_end = 0;
+    }
+
+  if (do_data_relro)
+    {
       lang_reset_memory_regions ();
       one_lang_size_sections_pass (relax, check_regions);
 
-      if (expld.dataseg.relro_end > relro_end)
+      /* Assignments to dot, or to output section address in a user
+        script have increased padding over the original.  Revert.  */
+      if (do_data_relro && expld.dataseg.relro_end > data_relro_end)
        {
-         /* Assignments to dot, or to output section address in a
-            user script have increased padding over the original.
-            Revert.  */
-         expld.dataseg.base = initial_base;
-         lang_reset_memory_regions ();
-         one_lang_size_sections_pass (relax, check_regions);
+         expld.dataseg.base = data_initial_base;;
+         do_reset = TRUE;
        }
-
-      link_info.relro_start = expld.dataseg.base;
-      link_info.relro_end = expld.dataseg.relro_end;
     }
-  else if (expld.dataseg.phase == exp_seg_end_seen)
+
+  if (!do_data_relro && lang_size_segment (&expld.dataseg))
+    do_reset = TRUE;
+
+  return do_reset;
+}
+
+void
+lang_size_sections (bfd_boolean *relax, bfd_boolean check_regions)
+{
+  expld.phase = lang_allocating_phase_enum;
+  expld.dataseg.phase = exp_seg_none;
+
+  one_lang_size_sections_pass (relax, check_regions);
+
+  if (expld.dataseg.phase != exp_seg_end_seen)
+    expld.dataseg.phase = exp_seg_done;
+
+  if (expld.dataseg.phase == exp_seg_end_seen)
     {
-      /* If DATA_SEGMENT_ALIGN DATA_SEGMENT_END pair was seen, check whether
-        a page could be saved in the data segment.  */
-      bfd_vma first, last;
+      bfd_boolean do_reset
+       = lang_size_relro_segment (relax, check_regions);
 
-      first = -expld.dataseg.base & (expld.dataseg.pagesize - 1);
-      last = expld.dataseg.end & (expld.dataseg.pagesize - 1);
-      if (first && last
-         && ((expld.dataseg.base & ~(expld.dataseg.pagesize - 1))
-             != (expld.dataseg.end & ~(expld.dataseg.pagesize - 1)))
-         && first + last <= expld.dataseg.pagesize)
+      if (do_reset)
        {
-         expld.dataseg.phase = exp_seg_adjust;
          lang_reset_memory_regions ();
          one_lang_size_sections_pass (relax, check_regions);
        }
-      else
-       expld.dataseg.phase = exp_seg_done;
+
+      if (link_info.relro && expld.dataseg.relro_end)
+       {
+         link_info.relro_start = expld.dataseg.base;
+         link_info.relro_end = expld.dataseg.relro_end;
+       }
     }
-  else
-    expld.dataseg.phase = exp_seg_done;
 }
 
 static lang_output_section_statement_type *current_section;
@@ -6031,6 +6235,24 @@ undef_start_stop (struct bfd_link_hash_entry *h)
       || strcmp (h->u.def.section->name,
                 h->u.def.section->output_section->name) != 0)
     {
+      asection *sec = bfd_get_section_by_name (link_info.output_bfd,
+                                              h->u.def.section->name);
+      if (sec != NULL)
+       {
+         /* When there are more than one input sections with the same
+            section name, SECNAME, linker picks the first one to define
+            __start_SECNAME and __stop_SECNAME symbols.  When the first
+            input section is removed by comdat group, we need to check
+            if there is still an output section with section name
+            SECNAME.  */
+         asection *i;
+         for (i = sec->map_head.s; i != NULL; i = i->map_head.s)
+           if (strcmp (h->u.def.section->name, i->name) == 0)
+             {
+               h->u.def.section = i;
+               return;
+             }
+       }
       h->type = bfd_link_hash_undefined;
       h->u.undef.abfd = NULL;
     }
@@ -6121,7 +6343,7 @@ lang_end (void)
      --gc-sections.  */
   if (link_info.gc_sections && bfd_link_relocatable (&link_info)
       && !(entry_from_cmdline || undef_from_cmdline))
-    einfo (_("%P%F: gc-sections requires either an entry or "
+    einfo (_("%F%P: gc-sections requires either an entry or "
             "an undefined symbol\n"));
 
   if (entry_symbol.name == NULL)
@@ -6146,7 +6368,7 @@ lang_end (void)
                                    h->u.def.section->output_section)
             + h->u.def.section->output_offset);
       if (!bfd_set_start_address (link_info.output_bfd, val))
-       einfo (_("%P%F:%s: can't set start address\n"), entry_symbol.name);
+       einfo (_("%F%P: %s: can't set start address\n"), entry_symbol.name);
     }
   else
     {
@@ -6159,7 +6381,7 @@ lang_end (void)
       if (*send == '\0')
        {
          if (!bfd_set_start_address (link_info.output_bfd, val))
-           einfo (_("%P%F: can't set start address\n"));
+           einfo (_("%F%P: can't set start address\n"));
        }
       else
        {
@@ -6178,7 +6400,7 @@ lang_end (void)
              if (!(bfd_set_start_address
                    (link_info.output_bfd,
                     bfd_get_section_vma (link_info.output_bfd, ts))))
-               einfo (_("%P%F: can't set start address\n"));
+               einfo (_("%F%P: can't set start address\n"));
            }
          else
            {
@@ -6237,8 +6459,8 @@ lang_check (void)
                  != bfd_get_flavour (link_info.output_bfd)))
          && (bfd_get_file_flags (input_bfd) & HAS_RELOC) != 0)
        {
-         einfo (_("%P%F: Relocatable linking with relocations from"
-                  " format %s (%B) to format %s (%B) is not supported\n"),
+         einfo (_("%F%P: relocatable linking with relocations from"
+                  " format %s (%pB) to format %s (%pB) is not supported\n"),
                 bfd_get_target (input_bfd), input_bfd,
                 bfd_get_target (link_info.output_bfd), link_info.output_bfd);
          /* einfo with %F exits.  */
@@ -6247,7 +6469,7 @@ lang_check (void)
       if (compatible == NULL)
        {
          if (command_line.warn_mismatch)
-           einfo (_("%P%X: %s architecture of input file `%B'"
+           einfo (_("%X%P: %s architecture of input file `%pB'"
                     " is incompatible with %s output\n"),
                   bfd_printable_name (input_bfd), input_bfd,
                   bfd_printable_name (link_info.output_bfd));
@@ -6269,8 +6491,8 @@ lang_check (void)
          if (!bfd_merge_private_bfd_data (input_bfd, &link_info))
            {
              if (command_line.warn_mismatch)
-               einfo (_("%P%X: failed to merge target specific data"
-                        " of file %B\n"), input_bfd);
+               einfo (_("%X%P: failed to merge target specific data"
+                        " of file %pB\n"), input_bfd);
            }
          if (!command_line.warn_mismatch)
            bfd_set_error_handler (pfn);
@@ -6340,7 +6562,7 @@ lang_one_common (struct bfd_link_hash_entry *h, void *info)
 
   section = h->u.c.p->section;
   if (!bfd_define_common_symbol (link_info.output_bfd, &link_info, h))
-    einfo (_("%P%F: Could not define common symbol `%T': %E\n"),
+    einfo (_("%F%P: could not define common symbol `%pT': %E\n"),
           h->root.string);
 
   if (config.map_file != NULL)
@@ -6396,7 +6618,7 @@ lang_one_common (struct bfd_link_hash_entry *h, void *info)
          ++len;
        }
 
-      minfo ("%B\n", section->owner);
+      minfo ("%pB\n", section->owner);
     }
 
   return TRUE;
@@ -6427,7 +6649,7 @@ ldlang_place_orphan (asection *s)
       int constraint = 0;
 
       if (config.orphan_handling == orphan_handling_error)
-       einfo (_("%X%P: error: unplaced orphan section `%A' from `%B'.\n"),
+       einfo (_("%X%P: error: unplaced orphan section `%pA' from `%pB'\n"),
               s, s->owner);
 
       if (config.unique_orphan_sections || unique_section_p (s, NULL))
@@ -6445,8 +6667,8 @@ ldlang_place_orphan (asection *s)
        }
 
       if (config.orphan_handling == orphan_handling_warn)
-       einfo (_("%P: warning: orphan section `%A' from `%B' being "
-                "placed in section `%s'.\n"),
+       einfo (_("%P: warning: orphan section `%pA' from `%pB' being "
+                "placed in section `%s'\n"),
               s, s->owner, os->name);
     }
 }
@@ -6536,7 +6758,7 @@ lang_set_flags (lang_memory_region_type *ptr, const char *flags, int invert)
          break;
 
        default:
-         einfo (_("%P%F: invalid character %c (%d) in flags\n"),
+         einfo (_("%F%P: invalid character %c (%d) in flags\n"),
                 *flags, *flags);
          break;
        }
@@ -6612,25 +6834,6 @@ lang_add_output (const char *name, int from_script)
     }
 }
 
-static int
-topower (int x)
-{
-  unsigned int i = 1;
-  int l;
-
-  if (x < 0)
-    return -1;
-
-  for (l = 0; l < 32; l++)
-    {
-      if (i >= (unsigned int) x)
-       return l;
-      i <<= 1;
-    }
-
-  return 0;
-}
-
 lang_output_section_statement_type *
 lang_enter_output_section_statement (const char *output_section_statement_name,
                                     etree_type *address_exp,
@@ -6663,13 +6866,11 @@ lang_enter_output_section_statement (const char *output_section_statement_name,
 
   os->align_lma_with_input = align_with_input == ALIGN_WITH_INPUT;
   if (os->align_lma_with_input && align != NULL)
-    einfo (_("%F%P:%S: error: align with input and explicit align specified\n"),
+    einfo (_("%F%P:%pS: error: align with input and explicit align specified\n"),
           NULL);
 
-  os->subsection_alignment =
-    topower (exp_get_value_int (subalign, -1, "subsection alignment"));
-  os->section_alignment =
-    topower (exp_get_value_int (align, -1, "section alignment"));
+  os->subsection_alignment = subalign;
+  os->section_alignment = align;
 
   os->load_base = ebase;
   return os;
@@ -6711,7 +6912,8 @@ lang_reset_memory_regions (void)
     {
       /* Save the last size for possible use by bfd_relax_section.  */
       o->rawsize = o->size;
-      o->size = 0;
+      if (!(o->flags & SEC_FIXED_SIZE))
+       o->size = 0;
     }
 }
 
@@ -6813,6 +7015,7 @@ find_relro_section_callback (lang_wild_statement_type *ptr ATTRIBUTE_UNUSED,
 
 static void
 lang_find_relro_sections_1 (lang_statement_union_type *s,
+                           seg_align_type *seg,
                            bfd_boolean *has_relro_section)
 {
   if (*has_relro_section)
@@ -6820,7 +7023,7 @@ lang_find_relro_sections_1 (lang_statement_union_type *s,
 
   for (; s != NULL; s = s->header.next)
     {
-      if (s == expld.dataseg.relro_end_stat)
+      if (s == seg->relro_end_stat)
        break;
 
       switch (s->header.type)
@@ -6832,15 +7035,15 @@ lang_find_relro_sections_1 (lang_statement_union_type *s,
          break;
        case lang_constructors_statement_enum:
          lang_find_relro_sections_1 (constructor_list.head,
-                                     has_relro_section);
+                                     seg, has_relro_section);
          break;
        case lang_output_section_statement_enum:
          lang_find_relro_sections_1 (s->output_section_statement.children.head,
-                                     has_relro_section);
+                                     seg, has_relro_section);
          break;
        case lang_group_statement_enum:
          lang_find_relro_sections_1 (s->group_statement.children.head,
-                                     has_relro_section);
+                                     seg, has_relro_section);
          break;
        default:
          break;
@@ -6856,7 +7059,7 @@ lang_find_relro_sections (void)
   /* Check all sections in the link script.  */
 
   lang_find_relro_sections_1 (expld.dataseg.relro_start_stat,
-                             &has_relro_section);
+                             &expld.dataseg, &has_relro_section);
 
   if (!has_relro_section)
     link_info.relro = FALSE;
@@ -6990,7 +7193,8 @@ find_rescan_insertion (lang_input_statement_type *add)
   for (iter = before ? &before->next : &file_chain.head->input_statement.next;
        *iter != NULL;
        iter = &(*iter)->input_statement.next)
-    if ((*iter)->input_statement.the_bfd->my_archive == NULL)
+    if (!(*iter)->input_statement.flags.claim_archive
+       && (*iter)->input_statement.the_bfd->my_archive == NULL)
       break;
 
   return iter;
@@ -7108,11 +7312,15 @@ lang_process (void)
   lang_place_undefineds ();
 
   if (!bfd_section_already_linked_table_init ())
-    einfo (_("%P%F: Failed to create hash table\n"));
+    einfo (_("%F%P: can not create hash table: %E\n"));
 
   /* Create a bfd for each input file.  */
   current_target = default_target;
+  lang_statement_iteration++;
   open_input_bfds (statement_list.head, OPEN_BFD_NORMAL);
+  /* open_input_bfds also handles assignments, so we can give values
+     to symbolic origin/length now.  */
+  lang_do_memory_regions ();
 
 #ifdef ENABLE_PLUGINS
   if (link_info.lto_plugin_active)
@@ -7131,7 +7339,7 @@ lang_process (void)
       files = file_chain;
       inputfiles = input_file_chain;
       if (plugin_call_all_symbols_read ())
-       einfo (_("%P%F: %s: plugin reported error after all symbols read\n"),
+       einfo (_("%F%P: %s: plugin reported error after all symbols read\n"),
               plugin_error_plugin ());
       /* Open any newly added files, updating the file chains.  */
       open_input_bfds (*added.tail, OPEN_BFD_NORMAL);
@@ -7167,6 +7375,7 @@ lang_process (void)
 
          /* Rescan archives in case new undefined symbols have appeared.  */
          files = file_chain;
+         lang_statement_iteration++;
          open_input_bfds (statement_list.head, OPEN_BFD_RESCAN);
          lang_list_remove_tail (&file_chain, &files);
          while (files.head != NULL)
@@ -7254,8 +7463,6 @@ lang_process (void)
   /* 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);
-
-  lang_do_memory_regions();
   expld.phase = lang_first_phase_enum;
 
   /* Size up the common data.  */
@@ -7340,8 +7547,11 @@ lang_process (void)
   /* 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.  */
+  /* Do all the assignments again, to report errors.  Assignment
+     statements are processed multiple times, updating symbols; In
+     open_input_bfds, lang_do_assignments, and lang_size_sections.
+     Since lang_relax_sections calls lang_do_assignments, symbols are
+     also updated in ldemul_after_allocation.  */
   lang_do_assignments (lang_final_phase_enum);
 
   ldemul_finish ();
@@ -7534,7 +7744,7 @@ lang_startup (const char *name)
 {
   if (first_file->filename != NULL)
     {
-      einfo (_("%P%F: multiple STARTUP files\n"));
+      einfo (_("%F%P: multiple STARTUP files\n"));
     }
   first_file->filename = name;
   first_file->local_sym_name = name;
@@ -7580,7 +7790,7 @@ lang_get_regions (lang_memory_region_type **region,
     *region = lang_memory_region_lookup (memspec, FALSE);
 
   if (have_lma && lma_memspec != 0)
-    einfo (_("%X%P:%S: section has both a load address and a load region\n"),
+    einfo (_("%X%P:%pS: section has both a load address and a load region\n"),
           NULL);
 }
 
@@ -7682,7 +7892,7 @@ lang_new_phdr (const char *name,
   n = (struct lang_phdr *) stat_alloc (sizeof (struct lang_phdr));
   n->next = NULL;
   n->name = name;
-  n->type = exp_get_value_int (type, 0, "program header type");
+  n->type = exp_get_vma (type, 0, "program header type");
   n->filehdr = filehdr;
   n->phdrs = phdrs;
   n->at = at;
@@ -7695,7 +7905,7 @@ lang_new_phdr (const char *name,
        && (*pp)->type == 1
        && !((*pp)->filehdr || (*pp)->phdrs))
       {
-       einfo (_("%X%P:%S: PHDRS and FILEHDR are not supported"
+       einfo (_("%X%P:%pS: PHDRS and FILEHDR are not supported"
                 " when prior PT_LOAD headers lack them\n"), NULL);
        hdrs = FALSE;
       }
This page took 0.039431 seconds and 4 git commands to generate.