]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - ld/ldlang.c
ld: Support customized output section type
[thirdparty/binutils-gdb.git] / ld / ldlang.c
index eaf90a63cba0b1850b9e90d8214befb322b2481d..1733f8e65c4d20786a5b7ad3eb896f378c3781ed 100644 (file)
@@ -1,5 +1,5 @@
 /* Linker command language support.
-   Copyright (C) 1991-2020 Free Software Foundation, Inc.
+   Copyright (C) 1991-2022 Free Software Foundation, Inc.
 
    This file is part of the GNU Binutils.
 
@@ -63,19 +63,12 @@ static struct obstack map_obstack;
 #define obstack_chunk_alloc xmalloc
 #define obstack_chunk_free free
 static const char *entry_symbol_default = "start";
-static bfd_boolean map_head_is_link_order = FALSE;
+static bool map_head_is_link_order = false;
 static lang_output_section_statement_type *default_common_section;
-static bfd_boolean map_option_f;
+static bool map_option_f;
 static bfd_vma print_dot;
 static lang_input_statement_type *first_file;
 static const char *current_target;
-/* Header for list of statements corresponding to any files involved in the
-   link, either specified from the command-line or added implicitely (eg.
-   archive member used to resolved undefined symbol, wildcard statement from
-   linker script, etc.).  Next pointer is in next field of a
-   lang_statement_header_type (reached via header field in a
-   lang_statement_union).  */
-static lang_statement_list_type statement_list;
 static lang_statement_list_type *stat_save[10];
 static lang_statement_list_type **stat_save_ptr = &stat_save[0];
 static struct unique_sections *unique_section_list;
@@ -86,23 +79,30 @@ static unsigned int opb_shift = 0;
 static void exp_init_os (etree_type *);
 static lang_input_statement_type *lookup_name (const char *);
 static void insert_undefined (const char *);
-static bfd_boolean sort_def_symbol (struct bfd_link_hash_entry *, void *);
+static bool sort_def_symbol (struct bfd_link_hash_entry *, void *);
 static void print_statement (lang_statement_union_type *,
                             lang_output_section_statement_type *);
 static void print_statement_list (lang_statement_union_type *,
                                  lang_output_section_statement_type *);
 static void print_statements (void);
-static void print_input_section (asection *, bfd_boolean);
-static bfd_boolean lang_one_common (struct bfd_link_hash_entry *, void *);
+static void print_input_section (asection *, bool);
+static bool lang_one_common (struct bfd_link_hash_entry *, void *);
 static void lang_record_phdrs (void);
 static void lang_do_version_exports_section (void);
 static void lang_finalize_version_expr_head
   (struct bfd_elf_version_expr_head *);
-static void lang_do_memory_regions (bfd_boolean);
+static void lang_do_memory_regions (bool);
 
 /* Exported variables.  */
 const char *output_target;
 lang_output_section_statement_type *abs_output_section;
+/* Header for list of statements corresponding to any files involved in the
+   link, either specified from the command-line or added implicitely (eg.
+   archive member used to resolved undefined symbol, wildcard statement from
+   linker script, etc.).  Next pointer is in next field of a
+   lang_statement_header_type (reached via header field in a
+   lang_statement_union).  */
+lang_statement_list_type statement_list;
 lang_statement_list_type lang_os_list;
 lang_statement_list_type *stat_ptr = &statement_list;
 /* Header for list of statements corresponding to files used in the final
@@ -122,11 +122,11 @@ struct bfd_elf_dynamic_list **current_dynamic_list_p;
 struct bfd_sym_chain entry_symbol = { NULL, NULL };
 const char *entry_section = ".text";
 struct lang_input_statement_flags input_flags;
-bfd_boolean entry_from_cmdline;
-bfd_boolean lang_has_input_file = FALSE;
-bfd_boolean had_output_filename = FALSE;
-bfd_boolean lang_float_flag = FALSE;
-bfd_boolean delete_output_file_on_failure = FALSE;
+bool entry_from_cmdline;
+bool lang_has_input_file = false;
+bool had_output_filename = false;
+bool lang_float_flag = false;
+bool delete_output_file_on_failure = false;
 struct lang_phdr *lang_phdr_list;
 struct lang_nocrossrefs *nocrossref_list;
 struct asneeded_minfo **asneeded_list_tail;
@@ -219,18 +219,18 @@ archive_path (const char *pattern)
 /* Given that FILE_SPEC results in a non-NULL SEP result from archive_path,
    return whether F matches FILE_SPEC.  */
 
-static bfd_boolean
+static bool
 input_statement_is_archive_path (const char *file_spec, char *sep,
                                 lang_input_statement_type *f)
 {
-  bfd_boolean match = FALSE;
+  bool match = false;
 
   if ((*(sep + 1) == 0
        || name_match (sep + 1, f->filename) == 0)
       && ((sep != file_spec)
          == (f->the_bfd != NULL && f->the_bfd->my_archive != NULL)))
     {
-      match = TRUE;
+      match = true;
 
       if (sep != file_spec)
        {
@@ -243,7 +243,7 @@ input_statement_is_archive_path (const char *file_spec, char *sep,
   return match;
 }
 
-static bfd_boolean
+static bool
 unique_section_p (const asection *sec,
                  const lang_output_section_statement_type *os)
 {
@@ -259,9 +259,9 @@ unique_section_p (const asection *sec,
   secnam = sec->name;
   for (unam = unique_section_list; unam; unam = unam->next)
     if (name_match (unam->name, secnam) == 0)
-      return TRUE;
+      return true;
 
-  return FALSE;
+  return false;
 }
 
 /* Generic traversal routines for finding matching sections.  */
@@ -269,7 +269,7 @@ unique_section_p (const asection *sec,
 /* Return true if FILE matches a pattern in EXCLUDE_LIST, otherwise return
    false.  */
 
-static bfd_boolean
+static bool
 walk_wild_file_in_exclude_list (struct name_list *exclude_list,
                                lang_input_statement_type *file)
 {
@@ -284,11 +284,11 @@ walk_wild_file_in_exclude_list (struct name_list *exclude_list,
       if (p != NULL)
        {
          if (input_statement_is_archive_path (list_tmp->name, p, file))
-           return TRUE;
+           return true;
        }
 
       else if (name_match (list_tmp->name, file->filename) == 0)
-       return TRUE;
+       return true;
 
       /* FIXME: Perhaps remove the following at some stage?  Matching
         unadorned archives like this was never documented and has
@@ -297,10 +297,10 @@ walk_wild_file_in_exclude_list (struct name_list *exclude_list,
               && file->the_bfd->my_archive != NULL
               && name_match (list_tmp->name,
                              bfd_get_filename (file->the_bfd->my_archive)) == 0)
-       return TRUE;
+       return true;
     }
 
-  return FALSE;
+  return false;
 }
 
 /* Try processing a section against a wildcard.  This just calls
@@ -320,7 +320,7 @@ walk_wild_consider_section (lang_wild_statement_type *ptr,
   if (walk_wild_file_in_exclude_list (sec->spec.exclude_name_list, file))
     return;
 
-  (*callback) (ptr, sec, s, ptr->section_flag_list, file, data);
+  (*callback) (ptr, sec, s, file, data);
 }
 
 /* Lowest common denominator routine that can handle everything correctly,
@@ -339,11 +339,11 @@ walk_wild_section_general (lang_wild_statement_type *ptr,
     {
       sec = ptr->section_list;
       if (sec == NULL)
-       (*callback) (ptr, sec, s, ptr->section_flag_list, file, data);
+       (*callback) (ptr, sec, s, file, data);
 
       while (sec != NULL)
        {
-         bfd_boolean skip = FALSE;
+         bool skip = false;
 
          if (sec->spec.name != NULL)
            {
@@ -366,30 +366,30 @@ walk_wild_section_general (lang_wild_statement_type *ptr,
 typedef struct
 {
   asection *found_section;
-  bfd_boolean multiple_sections_found;
+  bool multiple_sections_found;
 } section_iterator_callback_data;
 
-static bfd_boolean
+static bool
 section_iterator_callback (bfd *abfd ATTRIBUTE_UNUSED, asection *s, void *data)
 {
   section_iterator_callback_data *d = (section_iterator_callback_data *) data;
 
   if (d->found_section != NULL)
     {
-      d->multiple_sections_found = TRUE;
-      return TRUE;
+      d->multiple_sections_found = true;
+      return true;
     }
 
   d->found_section = s;
-  return FALSE;
+  return false;
 }
 
 static asection *
 find_section (lang_input_statement_type *file,
              struct wildcard_list *sec,
-             bfd_boolean *multiple_sections_found)
+             bool *multiple_sections_found)
 {
-  section_iterator_callback_data cb_data = { NULL, FALSE };
+  section_iterator_callback_data cb_data = { NULL, false };
 
   bfd_get_section_by_name_if (file->the_bfd, sec->spec.name,
                              section_iterator_callback, &cb_data);
@@ -403,29 +403,29 @@ find_section (lang_input_statement_type *file,
 /* A simple wild is a literal string followed by a single '*',
    where the literal part is at least 4 characters long.  */
 
-static bfd_boolean
+static bool
 is_simple_wild (const char *name)
 {
   size_t len = strcspn (name, "*?[");
   return len >= 4 && name[len] == '*' && name[len + 1] == '\0';
 }
 
-static bfd_boolean
+static bool
 match_simple_wild (const char *pattern, const char *name)
 {
   /* The first four characters of the pattern are guaranteed valid
      non-wildcard characters.  So we can go faster.  */
   if (pattern[0] != name[0] || pattern[1] != name[1]
       || pattern[2] != name[2] || pattern[3] != name[3])
-    return FALSE;
+    return false;
 
   pattern += 4;
   name += 4;
   while (*pattern != '*')
     if (*name++ != *pattern++)
-      return FALSE;
+      return false;
 
-  return TRUE;
+  return true;
 }
 
 /* Return the numerical value of the init_priority attribute from
@@ -566,7 +566,6 @@ static void
 output_section_callback_fast (lang_wild_statement_type *ptr,
                              struct wildcard_list *sec,
                              asection *section,
-                             struct flag_info *sflag_list ATTRIBUTE_UNUSED,
                              lang_input_statement_type *file,
                              void *output)
 {
@@ -583,6 +582,7 @@ output_section_callback_fast (lang_wild_statement_type *ptr,
   node->left = 0;
   node->right = 0;
   node->section = section;
+  node->pattern = ptr->section_list;
 
   tree = wild_sort_fast (ptr, sec, file, section);
   if (tree != NULL)
@@ -599,7 +599,7 @@ output_section_callback_tree_to_list (lang_wild_statement_type *ptr,
   if (tree->left)
     output_section_callback_tree_to_list (ptr, tree->left, output);
 
-  lang_add_section (&ptr->children, tree->section, NULL,
+  lang_add_section (&ptr->children, tree->section, tree->pattern, NULL,
                    (lang_output_section_statement_type *) output);
 
   if (tree->right)
@@ -622,7 +622,7 @@ walk_wild_section_specs1_wild0 (lang_wild_statement_type *ptr,
      (should be rare), we fall back to the general algorithm because
      we would otherwise have to sort the sections to make sure they
      get processed in the bfd's order.  */
-  bfd_boolean multiple_sections_found;
+  bool multiple_sections_found;
   struct wildcard_list *sec0 = ptr->handler_data[0];
   asection *s0 = find_section (file, sec0, &multiple_sections_found);
 
@@ -644,7 +644,7 @@ walk_wild_section_specs1_wild1 (lang_wild_statement_type *ptr,
   for (s = file->the_bfd->sections; s != NULL; s = s->next)
     {
       const char *sname = bfd_section_name (s);
-      bfd_boolean skip = !match_simple_wild (wildsec0->spec.name, sname);
+      bool skip = !match_simple_wild (wildsec0->spec.name, sname);
 
       if (!skip)
        walk_wild_consider_section (ptr, file, s, wildsec0, callback, data);
@@ -660,7 +660,7 @@ walk_wild_section_specs2_wild1 (lang_wild_statement_type *ptr,
   asection *s;
   struct wildcard_list *sec0 = ptr->handler_data[0];
   struct wildcard_list *wildsec1 = ptr->handler_data[1];
-  bfd_boolean multiple_sections_found;
+  bool multiple_sections_found;
   asection *s0 = find_section (file, sec0, &multiple_sections_found);
 
   if (multiple_sections_found)
@@ -681,7 +681,7 @@ walk_wild_section_specs2_wild1 (lang_wild_statement_type *ptr,
       else
        {
          const char *sname = bfd_section_name (s);
-         bfd_boolean skip = !match_simple_wild (wildsec1->spec.name, sname);
+         bool skip = !match_simple_wild (wildsec1->spec.name, sname);
 
          if (!skip)
            walk_wild_consider_section (ptr, file, s, wildsec1, callback,
@@ -700,7 +700,7 @@ walk_wild_section_specs3_wild2 (lang_wild_statement_type *ptr,
   struct wildcard_list *sec0 = ptr->handler_data[0];
   struct wildcard_list *wildsec1 = ptr->handler_data[1];
   struct wildcard_list *wildsec2 = ptr->handler_data[2];
-  bfd_boolean multiple_sections_found;
+  bool multiple_sections_found;
   asection *s0 = find_section (file, sec0, &multiple_sections_found);
 
   if (multiple_sections_found)
@@ -716,7 +716,7 @@ walk_wild_section_specs3_wild2 (lang_wild_statement_type *ptr,
       else
        {
          const char *sname = bfd_section_name (s);
-         bfd_boolean skip = !match_simple_wild (wildsec1->spec.name, sname);
+         bool skip = !match_simple_wild (wildsec1->spec.name, sname);
 
          if (!skip)
            walk_wild_consider_section (ptr, file, s, wildsec1, callback, data);
@@ -742,7 +742,7 @@ walk_wild_section_specs4_wild2 (lang_wild_statement_type *ptr,
   struct wildcard_list *sec1 = ptr->handler_data[1];
   struct wildcard_list *wildsec2 = ptr->handler_data[2];
   struct wildcard_list *wildsec3 = ptr->handler_data[3];
-  bfd_boolean multiple_sections_found;
+  bool multiple_sections_found;
   asection *s0 = find_section (file, sec0, &multiple_sections_found), *s1;
 
   if (multiple_sections_found)
@@ -768,8 +768,7 @@ walk_wild_section_specs4_wild2 (lang_wild_statement_type *ptr,
        else
          {
            const char *sname = bfd_section_name (s);
-           bfd_boolean skip = !match_simple_wild (wildsec2->spec.name,
-                                                  sname);
+           bool skip = !match_simple_wild (wildsec2->spec.name, sname);
 
            if (!skip)
              walk_wild_consider_section (ptr, file, s, wildsec2, callback,
@@ -802,7 +801,7 @@ walk_wild_section (lang_wild_statement_type *ptr,
    only if the prefixes of name1 and name2 are different up to the
    first wildcard character.  */
 
-static bfd_boolean
+static bool
 wild_spec_can_overlap (const char *name1, const char *name2)
 {
   size_t prefix1_len = strcspn (name1, "?*[");
@@ -1114,7 +1113,7 @@ new_afile (const char *name,
 {
   lang_input_statement_type *p;
 
-  lang_has_input_file = TRUE;
+  lang_has_input_file = true;
 
   p = new_stat (lang_input_statement, stat_ptr);
   memset (&p->the_bfd, 0,
@@ -1132,8 +1131,8 @@ new_afile (const char *name,
     case lang_input_file_is_symbols_only_enum:
       p->filename = name;
       p->local_sym_name = name;
-      p->flags.real = TRUE;
-      p->flags.just_syms = TRUE;
+      p->flags.real = true;
+      p->flags.just_syms = true;
       break;
     case lang_input_file_is_fake_enum:
       p->filename = name;
@@ -1143,19 +1142,19 @@ new_afile (const char *name,
       if (name[0] == ':' && name[1] != '\0')
        {
          p->filename = name + 1;
-         p->flags.full_name_provided = TRUE;
+         p->flags.full_name_provided = true;
        }
       else
        p->filename = name;
       p->local_sym_name = concat ("-l", name, (const char *) NULL);
-      p->flags.maybe_archive = TRUE;
-      p->flags.real = TRUE;
-      p->flags.search_dirs = TRUE;
+      p->flags.maybe_archive = true;
+      p->flags.real = true;
+      p->flags.search_dirs = true;
       break;
     case lang_input_file_is_marker_enum:
       p->filename = name;
       p->local_sym_name = name;
-      p->flags.search_dirs = TRUE;
+      p->flags.search_dirs = true;
       break;
     case lang_input_file_is_search_file_enum:
       p->filename = name;
@@ -1164,13 +1163,13 @@ new_afile (const char *name,
          script first. */
       if (from_filename && !IS_ABSOLUTE_PATH (name))
         p->extra_search_path = ldirname (from_filename);
-      p->flags.real = TRUE;
-      p->flags.search_dirs = TRUE;
+      p->flags.real = true;
+      p->flags.search_dirs = true;
       break;
     case lang_input_file_is_file_enum:
       p->filename = name;
       p->local_sym_name = name;
-      p->flags.real = TRUE;
+      p->flags.real = true;
       break;
     default:
       FAIL ();
@@ -1186,7 +1185,7 @@ lang_add_input_file (const char *name,
                     const char *target)
 {
   if (name != NULL
-      && (*name == '=' || CONST_STRNEQ (name, "$SYSROOT")))
+      && (*name == '=' || startswith (name, "$SYSROOT")))
     {
       lang_input_statement_type *ret;
       char *sysrooted_name
@@ -1305,7 +1304,7 @@ lang_init (void)
   first_file = lang_add_input_file (NULL, lang_input_file_is_marker_enum,
                                    NULL);
   abs_output_section =
-    lang_output_section_statement_lookup (BFD_ABS_SECTION_NAME, 0, TRUE);
+    lang_output_section_statement_lookup (BFD_ABS_SECTION_NAME, 0, 1);
 
   abs_output_section->bfd_section = bfd_abs_section_ptr;
 
@@ -1346,7 +1345,7 @@ static lang_memory_region_type **lang_memory_region_list_tail
   = &lang_memory_region_list;
 
 lang_memory_region_type *
-lang_memory_region_lookup (const char *const name, bfd_boolean create)
+lang_memory_region_lookup (const char *const name, bool create)
 {
   lang_memory_region_name *n;
   lang_memory_region_type *r;
@@ -1383,7 +1382,7 @@ lang_memory_region_lookup (const char *const name, bfd_boolean create)
   new_region->last_os = NULL;
   new_region->flags = 0;
   new_region->not_flags = 0;
-  new_region->had_full_message = FALSE;
+  new_region->had_full_message = false;
 
   *lang_memory_region_list_tail = new_region;
   lang_memory_region_list_tail = &new_region->next;
@@ -1451,7 +1450,7 @@ lang_memory_default (asection *section)
          return p;
        }
     }
-  return lang_memory_region_lookup (DEFAULT_MEMORY_REGION, FALSE);
+  return lang_memory_region_lookup (DEFAULT_MEMORY_REGION, false);
 }
 
 /* Get the output section statement directly from the userdata.  */
@@ -1464,19 +1463,21 @@ lang_output_section_get (const asection *output_section)
 
 /* Find or create an output_section_statement with the given NAME.
    If CONSTRAINT is non-zero match one with that constraint, otherwise
-   match any non-negative constraint.  If CREATE, always make a
-   new output_section_statement for SPECIAL CONSTRAINT.  */
+   match any non-negative constraint.  If CREATE is 0 return NULL when
+   no match exists.  If CREATE is 1, create an output_section_statement
+   when no match exists or if CONSTRAINT is SPECIAL.  If CREATE is 2,
+   always make a new output_section_statement.  */
 
 lang_output_section_statement_type *
 lang_output_section_statement_lookup (const char *name,
                                      int constraint,
-                                     bfd_boolean create)
+                                     int create)
 {
   struct out_section_hash_entry *entry;
 
   entry = ((struct out_section_hash_entry *)
           bfd_hash_lookup (&output_section_statement_table, name,
-                           create, FALSE));
+                           create != 0, false));
   if (entry == NULL)
     {
       if (create)
@@ -1491,23 +1492,19 @@ lang_output_section_statement_lookup (const char *name,
       struct out_section_hash_entry *last_ent;
 
       name = entry->s.output_section_statement.name;
-      if (create && constraint == SPECIAL)
-       /* Not traversing to the end reverses the order of the second
-          and subsequent SPECIAL sections in the hash table chain,
-          but that shouldn't matter.  */
-       last_ent = entry;
-      else
-       do
-         {
-           if (constraint == entry->s.output_section_statement.constraint
-               || (constraint == 0
-                   && entry->s.output_section_statement.constraint >= 0))
-             return &entry->s.output_section_statement;
-           last_ent = entry;
-           entry = (struct out_section_hash_entry *) entry->root.next;
-         }
-       while (entry != NULL
-              && name == entry->s.output_section_statement.name);
+      do
+       {
+         if (create != 2
+             && !(create && constraint == SPECIAL)
+             && (constraint == entry->s.output_section_statement.constraint
+                 || (constraint == 0
+                     && entry->s.output_section_statement.constraint >= 0)))
+           return &entry->s.output_section_statement;
+         last_ent = entry;
+         entry = (struct out_section_hash_entry *) entry->root.next;
+       }
+      while (entry != NULL
+            && name == entry->s.output_section_statement.name);
 
       if (!create)
        return NULL;
@@ -1528,6 +1525,8 @@ lang_output_section_statement_lookup (const char *name,
 
   entry->s.output_section_statement.name = name;
   entry->s.output_section_statement.constraint = constraint;
+  entry->s.output_section_statement.dup_output = (create == 2
+                                                 || constraint == SPECIAL);
   return &entry->s.output_section_statement;
 }
 
@@ -1655,7 +1654,7 @@ lang_output_section_find_by_flags (const asection *sec,
     {
       /* .tdata can go after .data, .tbss after .tdata.  Treat .tbss
         as if it were a loaded section, and don't use match_type.  */
-      bfd_boolean seen_thread_local = FALSE;
+      bool seen_thread_local = false;
 
       match_type = NULL;
       for (look = first; look; look = look->next)
@@ -1675,7 +1674,7 @@ lang_output_section_find_by_flags (const asection *sec,
                   previous section.  */
                break;
              found = look;
-             seen_thread_local = TRUE;
+             seen_thread_local = true;
            }
          else if (seen_thread_local)
            break;
@@ -1803,7 +1802,7 @@ insert_os_after (lang_output_section_statement_type *after)
 {
   lang_statement_union_type **where;
   lang_statement_union_type **assign = NULL;
-  bfd_boolean ignore_first;
+  bool ignore_first;
 
   ignore_first = after == (void *) lang_os_list.head;
 
@@ -1825,7 +1824,7 @@ insert_os_after (lang_output_section_statement_type *after)
                {
                  if (!ignore_first)
                    assign = where;
-                 ignore_first = FALSE;
+                 ignore_first = false;
                }
            }
          continue;
@@ -1838,7 +1837,7 @@ insert_os_after (lang_output_section_statement_type *after)
        case lang_padding_statement_enum:
        case lang_constructors_statement_enum:
          assign = NULL;
-         ignore_first = FALSE;
+         ignore_first = false;
          continue;
        case lang_output_section_statement_enum:
          if (assign != NULL)
@@ -1892,12 +1891,12 @@ lang_insert_orphan (asection *s,
     address = exp_intop (0);
 
   os_tail = (lang_output_section_statement_type **) lang_os_list.tail;
-  os = lang_enter_output_section_statement (secname, address, normal_section,
-                                           NULL, NULL, NULL, constraint, 0);
+  os = lang_enter_output_section_statement (
+      secname, address, normal_section, 0, NULL, NULL, NULL, constraint, 0);
 
   if (add_child == NULL)
     add_child = &os->children;
-  lang_add_section (add_child, s, NULL, os);
+  lang_add_section (add_child, s, NULL, NULL, os);
 
   if (after && (s->flags & (SEC_LOAD | SEC_ALLOC)) != 0)
     {
@@ -1921,8 +1920,8 @@ lang_insert_orphan (asection *s,
   if (after != NULL && os->bfd_section != NULL)
     {
       asection *snew, *as;
-      bfd_boolean place_after = place->stmt == NULL;
-      bfd_boolean insert_after = TRUE;
+      bool place_after = place->stmt == NULL;
+      bool insert_after = true;
 
       snew = os->bfd_section;
 
@@ -1977,7 +1976,7 @@ lang_insert_orphan (asection *s,
          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 = FALSE;
+         bool after_sec_note = false;
 
          static asection *first_orphan_note = NULL;
 
@@ -2021,14 +2020,14 @@ lang_insert_orphan (asection *s,
                     alignments, place the section before all
                     output orphan note sections.  */
                  after_sec = first_orphan_note;
-                 insert_after = FALSE;
+                 insert_after = false;
                }
            }
          else if (first_orphan_note)
            {
              /* Don't place non-note sections in the middle of orphan
                 note sections.  */
-             after_sec_note = TRUE;
+             after_sec_note = true;
              after_sec = as;
              for (sec = as->next;
                   (sec != NULL
@@ -2046,7 +2045,7 @@ lang_insert_orphan (asection *s,
                  /* Search forward to insert OS after AFTER_SEC output
                     statement.  */
                  lang_output_section_statement_type *stmt, *next;
-                 bfd_boolean found = FALSE;
+                 bool found = false;
                  for (stmt = after; stmt != NULL; stmt = next)
                    {
                      next = stmt->next;
@@ -2054,8 +2053,8 @@ lang_insert_orphan (asection *s,
                        {
                          if (stmt->bfd_section == after_sec)
                            {
-                             place_after = TRUE;
-                             found = TRUE;
+                             place_after = true;
+                             found = true;
                              after = stmt;
                              break;
                            }
@@ -2066,8 +2065,8 @@ lang_insert_orphan (asection *s,
                             AFTER_SEC output statement.  */
                          if (next && next->bfd_section == after_sec)
                            {
-                             place_after = TRUE;
-                             found = TRUE;
+                             place_after = true;
+                             found = true;
                              after = stmt;
                              break;
                            }
@@ -2083,7 +2082,7 @@ lang_insert_orphan (asection *s,
                          {
                            if (stmt->bfd_section == after_sec)
                              {
-                               place_after = TRUE;
+                               place_after = true;
                                after = stmt;
                                break;
                              }
@@ -2094,7 +2093,7 @@ lang_insert_orphan (asection *s,
                               AFTER_SEC output statement.  */
                            if (stmt->next->bfd_section == after_sec)
                              {
-                               place_after = TRUE;
+                               place_after = true;
                                after = stmt;
                                break;
                              }
@@ -2266,7 +2265,7 @@ void
 lang_map (void)
 {
   lang_memory_region_type *m;
-  bfd_boolean dis_header_printed = FALSE;
+  bool dis_header_printed = false;
 
   LANG_FOR_EACH_INPUT_STATEMENT (file)
     {
@@ -2285,10 +2284,10 @@ lang_map (void)
              if (! dis_header_printed)
                {
                  fprintf (config.map_file, _("\nDiscarded input sections\n\n"));
-                 dis_header_printed = TRUE;
+                 dis_header_printed = true;
                }
 
-             print_input_section (s, TRUE);
+             print_input_section (s, true);
            }
     }
 
@@ -2349,7 +2348,7 @@ lang_map (void)
                              config.map_file);
 }
 
-static bfd_boolean
+static bool
 sort_def_symbol (struct bfd_link_hash_entry *hash_entry,
                 void *info ATTRIBUTE_UNUSED)
 {
@@ -2378,7 +2377,7 @@ sort_def_symbol (struct bfd_link_hash_entry *hash_entry,
       ud->map_symbol_def_tail = &def->next;
       ud->map_symbol_def_count++;
     }
-  return TRUE;
+  return true;
 }
 
 /* Initialize an output section.  */
@@ -2389,7 +2388,7 @@ init_os (lang_output_section_statement_type *s, flagword flags)
   if (strcmp (s->name, DISCARD_SECTION_NAME) == 0)
     einfo (_("%F%P: illegal use of `%s' section\n"), DISCARD_SECTION_NAME);
 
-  if (s->constraint != SPECIAL)
+  if (!s->dup_output)
     s->bfd_section = bfd_get_section_by_name (link_info.output_bfd, s->name);
   if (s->bfd_section == NULL)
     s->bfd_section = bfd_make_section_anyway_with_flags (link_info.output_bfd,
@@ -2502,10 +2501,10 @@ section_already_linked (bfd *abfd, asection *sec, void *data)
 /* Returns true if SECTION is one we know will be discarded based on its
    section flags, otherwise returns false.  */
 
-static bfd_boolean
+static bool
 lang_discard_section_p (asection *section)
 {
-  bfd_boolean discard;
+  bool discard;
   flagword flags = section->flags;
 
   /* Discard sections marked with SEC_EXCLUDE.  */
@@ -2515,13 +2514,13 @@ lang_discard_section_p (asection *section)
      sections from within the group.  */
   if ((flags & SEC_GROUP) != 0
       && link_info.resolve_section_groups)
-    discard = TRUE;
+    discard = true;
 
   /* Discard debugging sections if we are stripping debugging
      information.  */
   if ((link_info.strip == strip_debugger || link_info.strip == strip_all)
       && (flags & SEC_DEBUGGING) != 0)
-    discard = TRUE;
+    discard = true;
 
   return discard;
 }
@@ -2538,12 +2537,13 @@ lang_discard_section_p (asection *section)
 void
 lang_add_section (lang_statement_list_type *ptr,
                  asection *section,
+                 struct wildcard_list *pattern,
                  struct flag_info *sflag_info,
                  lang_output_section_statement_type *output)
 {
   flagword flags = section->flags;
 
-  bfd_boolean discard;
+  bool discard;
   lang_input_section_type *new_section;
   bfd *abfd = link_info.output_bfd;
 
@@ -2553,7 +2553,7 @@ lang_add_section (lang_statement_list_type *ptr,
   /* Discard input sections which are assigned to a section named
      DISCARD_SECTION_NAME.  */
   if (strcmp (output->name, DISCARD_SECTION_NAME) == 0)
-    discard = TRUE;
+    discard = true;
 
   if (discard)
     {
@@ -2572,7 +2572,7 @@ lang_add_section (lang_statement_list_type *ptr,
 
   if (sflag_info)
     {
-      bfd_boolean keep;
+      bool keep;
 
       keep = bfd_lookup_section_flags (&link_info, sflag_info, section);
       if (!keep)
@@ -2635,10 +2635,15 @@ lang_add_section (lang_statement_list_type *ptr,
     case normal_section:
     case overlay_section:
     case first_overlay_section:
+    case type_section:
       break;
     case noalloc_section:
       flags &= ~SEC_ALLOC;
       break;
+    case typed_readonly_section:
+    case readonly_section:
+      flags |= SEC_READONLY;
+      break;
     case noload_section:
       flags &= ~SEC_LOAD;
       flags |= SEC_NEVER_LOAD;
@@ -2698,6 +2703,16 @@ lang_add_section (lang_statement_list_type *ptr,
       output->block_value = 128;
     }
 
+  /* When a .ctors section is placed in .init_array it must be copied
+     in reverse order.  Similarly for .dtors.  Set that up.  */
+  if (bfd_get_flavour (link_info.output_bfd) == bfd_target_elf_flavour
+      && ((startswith (section->name, ".ctors")
+          && strcmp (output->bfd_section->name, ".init_array") == 0)
+         || (startswith (section->name, ".dtors")
+             && strcmp (output->bfd_section->name, ".fini_array") == 0))
+      && (section->name[6] == 0 || section->name[6] == '.'))
+    section->flags |= SEC_ELF_REVERSE_COPY;
+
   if (section->alignment_power > output->bfd_section->alignment_power)
     output->bfd_section->alignment_power = section->alignment_power;
 
@@ -2718,6 +2733,7 @@ lang_add_section (lang_statement_list_type *ptr,
   /* Add a section reference to the list.  */
   new_section = new_stat (lang_input_section, ptr);
   new_section->section = section;
+  new_section->pattern = pattern;
 }
 
 /* Handle wildcard sorting.  This returns the lang_input_section which
@@ -2751,7 +2767,7 @@ wild_sort (lang_wild_statement_type *wild,
       if (wild->filenames_sorted)
        {
          const char *fn, *ln;
-         bfd_boolean fa, la;
+         bool fa, la;
          int i;
 
          /* The PE support for the .idata section as generated by
@@ -2763,23 +2779,23 @@ wild_sort (lang_wild_statement_type *wild,
              && file->the_bfd->my_archive != NULL)
            {
              fn = bfd_get_filename (file->the_bfd->my_archive);
-             fa = TRUE;
+             fa = true;
            }
          else
            {
              fn = file->filename;
-             fa = FALSE;
+             fa = false;
            }
 
          if (ls->section->owner->my_archive != NULL)
            {
              ln = bfd_get_filename (ls->section->owner->my_archive);
-             la = TRUE;
+             la = true;
            }
          else
            {
              ln = bfd_get_filename (ls->section->owner);
-             la = FALSE;
+             la = false;
            }
 
          i = filename_cmp (fn, ln);
@@ -2823,7 +2839,6 @@ static void
 output_section_callback (lang_wild_statement_type *ptr,
                         struct wildcard_list *sec,
                         asection *section,
-                        struct flag_info *sflag_info,
                         lang_input_statement_type *file,
                         void *output)
 {
@@ -2844,14 +2859,16 @@ output_section_callback (lang_wild_statement_type *ptr,
      of the current list.  */
 
   if (before == NULL)
-    lang_add_section (&ptr->children, section, sflag_info, os);
+    lang_add_section (&ptr->children, section, ptr->section_list,
+                     ptr->section_flag_list, os);
   else
     {
       lang_statement_list_type list;
       lang_statement_union_type **pp;
 
       lang_list_init (&list);
-      lang_add_section (&list, section, sflag_info, os);
+      lang_add_section (&list, section, ptr->section_list,
+                       ptr->section_flag_list, os);
 
       /* If we are discarding the section, LIST.HEAD will
         be NULL.  */
@@ -2877,7 +2894,6 @@ static void
 check_section_callback (lang_wild_statement_type *ptr ATTRIBUTE_UNUSED,
                        struct wildcard_list *sec ATTRIBUTE_UNUSED,
                        asection *section,
-                       struct flag_info *sflag_info ATTRIBUTE_UNUSED,
                        lang_input_statement_type *file ATTRIBUTE_UNUSED,
                        void *output)
 {
@@ -2890,7 +2906,7 @@ check_section_callback (lang_wild_statement_type *ptr ATTRIBUTE_UNUSED,
     return;
 
   if (section->output_section == NULL && (section->flags & SEC_READONLY) == 0)
-    os->all_input_readonly = FALSE;
+    os->all_input_readonly = false;
 }
 
 /* This is passed a file name which must have been seen already and
@@ -2992,7 +3008,7 @@ check_excluded_libs (bfd *abfd)
 
       if (strcmp (lib->name, "ALL") == 0)
        {
-         abfd->no_export = TRUE;
+         abfd->no_export = true;
          return;
        }
 
@@ -3001,7 +3017,7 @@ check_excluded_libs (bfd *abfd)
              || (filename[len] == '.' && filename[len + 1] == 'a'
                  && filename[len + 2] == '\0')))
        {
-         abfd->no_export = TRUE;
+         abfd->no_export = true;
          return;
        }
 
@@ -3011,20 +3027,20 @@ check_excluded_libs (bfd *abfd)
 
 /* Get the symbols for an input file.  */
 
-bfd_boolean
+bool
 load_symbols (lang_input_statement_type *entry,
              lang_statement_list_type *place)
 {
   char **matching;
 
   if (entry->flags.loaded)
-    return TRUE;
+    return true;
 
   ldfile_open_file (entry);
 
   /* Do not process further if the file was missing.  */
   if (entry->flags.missing_file)
-    return TRUE;
+    return true;
 
   if (trace_files || verbose)
     info_msg ("%pI\n", entry);
@@ -3040,7 +3056,7 @@ load_symbols (lang_input_statement_type *entry,
 
       /* See if the emulation has some special knowledge.  */
       if (ldemul_unrecognized_file (entry))
-       return TRUE;
+       return true;
 
       if (err == bfd_error_file_ambiguously_recognized)
        {
@@ -3071,12 +3087,12 @@ load_symbols (lang_input_statement_type *entry,
       input_flags.whole_archive = entry->flags.whole_archive;
       input_flags.dynamic = entry->flags.dynamic;
 
-      ldfile_assumed_script = TRUE;
+      ldfile_assumed_script = true;
       parser_input = input_script;
       current_input_file = entry->filename;
       yyparse ();
       current_input_file = NULL;
-      ldfile_assumed_script = FALSE;
+      ldfile_assumed_script = false;
 
       /* missing_file is sticky.  sysrooted will already have been
         restored when seeing EOF in yyparse, but no harm to restore
@@ -3086,13 +3102,13 @@ load_symbols (lang_input_statement_type *entry,
       pop_stat_ptr ();
       fclose (yyin);
       yyin = NULL;
-      entry->flags.loaded = TRUE;
+      entry->flags.loaded = true;
 
-      return TRUE;
+      return true;
     }
 
   if (ldemul_recognized_file (entry))
-    return TRUE;
+    return true;
 
   /* We don't call ldlang_add_file for an archive.  Instead, the
      add_symbols entry point will call ldlang_add_file, via the
@@ -3115,7 +3131,7 @@ load_symbols (lang_input_statement_type *entry,
       if (entry->flags.whole_archive)
        {
          bfd *member = NULL;
-         bfd_boolean loaded = TRUE;
+         bool loaded = true;
 
          for (;;)
            {
@@ -3129,7 +3145,7 @@ load_symbols (lang_input_statement_type *entry,
                {
                  einfo (_("%F%P: %pB: member %pB in archive is not an object\n"),
                         entry->the_bfd, member);
-                 loaded = FALSE;
+                 loaded = false;
                }
 
              subsbfd = member;
@@ -3143,7 +3159,7 @@ load_symbols (lang_input_statement_type *entry,
              if (!bfd_link_add_symbols (subsbfd, &link_info))
                {
                  einfo (_("%F%P: %pB: error adding symbols: %E\n"), member);
-                 loaded = FALSE;
+                 loaded = false;
                }
            }
 
@@ -3154,7 +3170,7 @@ load_symbols (lang_input_statement_type *entry,
     }
 
   if (bfd_link_add_symbols (entry->the_bfd, &link_info))
-    entry->flags.loaded = TRUE;
+    entry->flags.loaded = true;
   else
     einfo (_("%F%P: %pB: error adding symbols: %E\n"), entry->the_bfd);
 
@@ -3388,6 +3404,22 @@ lang_get_output_target (void)
 static void
 open_output (const char *name)
 {
+  lang_input_statement_type *f;
+  char *out = lrealpath (name);
+
+  for (f = (void *) input_file_chain.head;
+       f != NULL;
+       f = f->next_real_file)
+    if (f->flags.real)
+      {
+       char *in = lrealpath (f->local_sym_name);
+       if (filename_cmp (in, out) == 0)
+         einfo (_("%F%P: input file '%s' is the same as output file\n"),
+                f->filename);
+       free (in);
+      }
+  free (out);
+
   output_target = lang_get_output_target ();
 
   /* Has the user requested a particular endianness on the command
@@ -3449,7 +3481,7 @@ open_output (const char *name)
       einfo (_("%F%P: cannot open output file %s: %E\n"), name);
     }
 
-  delete_output_file_on_failure = TRUE;
+  delete_output_file_on_failure = true;
 
   if (!bfd_set_format (link_info.output_bfd, bfd_object))
     einfo (_("%F%P: %s: can not make object file: %E\n"), name);
@@ -3616,15 +3648,15 @@ open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode)
                          && bfd_get_flavour (abfd) == bfd_target_elf_flavour
                          && (elf_dyn_lib_class (abfd) & DYN_AS_NEEDED) != 0)))
                {
-                 s->input_statement.flags.loaded = FALSE;
-                 s->input_statement.flags.reload = TRUE;
+                 s->input_statement.flags.loaded = false;
+                 s->input_statement.flags.reload = true;
                }
 
              os_tail = lang_os_list.tail;
              lang_list_init (&add);
 
              if (!load_symbols (&s->input_statement, &add))
-               config.make_executable = FALSE;
+               config.make_executable = false;
 
              if (add.head != NULL)
                {
@@ -3809,6 +3841,8 @@ lang_merge_ctf (void)
     flags = CTF_LINK_SHARE_DUPLICATED;
   if (!config.ctf_variables)
     flags |= CTF_LINK_OMIT_VARIABLES_SECTION;
+  if (bfd_link_relocatable (&link_info))
+    flags |= CTF_LINK_NO_FILTER_REPORTED_SYMS;
 
   if (ctf_link (ctf_output, flags) < 0)
     {
@@ -3826,14 +3860,20 @@ lang_merge_ctf (void)
   lang_ctf_errs_warnings (ctf_output);
 }
 
-/* Let the emulation examine the symbol table and strtab to help it optimize the
-   CTF, if supported.  */
+/* Let the emulation acquire strings from the dynamic strtab to help it optimize
+   the CTF, if supported.  */
 
 void
-ldlang_ctf_apply_strsym (struct elf_sym_strtab *syms, bfd_size_type symcount,
-                        struct elf_strtab_hash *symstrtab)
+ldlang_ctf_acquire_strings (struct elf_strtab_hash *dynstrtab)
 {
-  ldemul_examine_strtab_for_ctf (ctf_output, syms, symcount, symstrtab);
+  ldemul_acquire_strings_for_ctf (ctf_output, dynstrtab);
+}
+
+/* Inform the emulation about the addition of a new dynamic symbol, in BFD
+   internal format.  */
+void ldlang_ctf_new_dynsym (int symidx, struct elf_internal_sym *sym)
+{
+  ldemul_new_dynsym_for_ctf (ctf_output, symidx, sym);
 }
 
 /* Write out the CTF section.  Called early, if the emulation isn't going to
@@ -3860,6 +3900,11 @@ lang_write_ctf (int late)
        return;
     }
 
+  /* Inform the emulation that all the symbols that will be received have
+     been.  */
+
+  ldemul_new_dynsym_for_ctf (ctf_output, 0, NULL);
+
   /* Emit CTF.  */
 
   output_sect = bfd_get_section_by_name (link_info.output_bfd, ".ctf");
@@ -3922,11 +3967,11 @@ ldlang_open_ctf (void)
 
 static void lang_merge_ctf (void) {}
 void
-ldlang_ctf_apply_strsym (struct elf_sym_strtab *syms ATTRIBUTE_UNUSED,
-                        bfd_size_type symcount ATTRIBUTE_UNUSED,
-                        struct elf_strtab_hash *symstrtab ATTRIBUTE_UNUSED)
-{
-}
+ldlang_ctf_acquire_strings (struct elf_strtab_hash *dynstrtab
+                           ATTRIBUTE_UNUSED) {}
+void
+ldlang_ctf_new_dynsym (int symidx ATTRIBUTE_UNUSED,
+                      struct elf_internal_sym *sym ATTRIBUTE_UNUSED) {}
 static void lang_write_ctf (int late ATTRIBUTE_UNUSED) {}
 void ldlang_write_ctf_late (void) {}
 #endif
@@ -3942,7 +3987,7 @@ typedef struct bfd_sym_chain ldlang_undef_chain_list_type;
 #define ldlang_undef_chain_list_head entry_symbol.next
 
 void
-ldlang_add_undef (const char *const name, bfd_boolean cmdline ATTRIBUTE_UNUSED)
+ldlang_add_undef (const char *const name, bool cmdline ATTRIBUTE_UNUSED)
 {
   ldlang_undef_chain_list_type *new_undef;
 
@@ -3963,16 +4008,14 @@ insert_undefined (const char *name)
 {
   struct bfd_link_hash_entry *h;
 
-  h = bfd_link_hash_lookup (link_info.hash, name, TRUE, FALSE, TRUE);
+  h = bfd_link_hash_lookup (link_info.hash, name, true, false, true);
   if (h == NULL)
     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;
+      h->non_ir_ref_regular = true;
       bfd_link_add_undef (link_info.hash, h);
     }
 }
@@ -3990,6 +4033,23 @@ lang_place_undefineds (void)
     insert_undefined (ptr->name);
 }
 
+/* Mark -u symbols against garbage collection.  */
+
+static void
+lang_mark_undefineds (void)
+{
+  ldlang_undef_chain_list_type *ptr;
+
+  if (is_elf_hash_table (link_info.hash))
+    for (ptr = ldlang_undef_chain_list_head; ptr != NULL; ptr = ptr->next)
+      {
+       struct elf_link_hash_entry *h = (struct elf_link_hash_entry *)
+         bfd_link_hash_lookup (link_info.hash, ptr->name, false, false, true);
+       if (h != NULL)
+         h->mark = 1;
+      }
+}
+
 /* Structure used to build the list of symbols that the user has required
    be defined.  */
 
@@ -4011,7 +4071,7 @@ ldlang_add_require_defined (const char *const name)
 {
   struct require_defined_symbol *ptr;
 
-  ldlang_add_undef (name, TRUE);
+  ldlang_add_undef (name, true);
   ptr = stat_alloc (sizeof (*ptr));
   ptr->next = require_defined_symbol_list;
   ptr->name = strdup (name);
@@ -4031,7 +4091,7 @@ ldlang_check_require_defined_symbols (void)
       struct bfd_link_hash_entry *h;
 
       h = bfd_link_hash_lookup (link_info.hash, ptr->name,
-                               FALSE, FALSE, TRUE);
+                               false, false, true);
       if (h == NULL
          || (h->type != bfd_link_hash_defined
              && h->type != bfd_link_hash_defweak))
@@ -4151,6 +4211,7 @@ map_input_to_output_sections
     {
       lang_output_section_statement_type *tos;
       flagword flags;
+      unsigned int type = 0;
 
       switch (s->header.type)
        {
@@ -4164,22 +4225,18 @@ map_input_to_output_sections
          break;
        case lang_output_section_statement_enum:
          tos = &s->output_section_statement;
-         if (tos->constraint != 0)
+         if (tos->constraint == ONLY_IF_RW
+             || tos->constraint == ONLY_IF_RO)
            {
-             if (tos->constraint != ONLY_IF_RW
-                 && tos->constraint != ONLY_IF_RO)
-               break;
-             tos->all_input_readonly = TRUE;
+             tos->all_input_readonly = true;
              check_input_sections (tos->children.head, tos);
              if (tos->all_input_readonly != (tos->constraint == ONLY_IF_RO))
-               {
-                 tos->constraint = -1;
-                 break;
-               }
+               tos->constraint = -1;
            }
-         map_input_to_output_sections (tos->children.head,
-                                       target,
-                                       tos);
+         if (tos->constraint >= 0)
+           map_input_to_output_sections (tos->children.head,
+                                         target,
+                                         tos);
          break;
        case lang_output_statement_enum:
          break;
@@ -4207,6 +4264,45 @@ map_input_to_output_sections
            case noalloc_section:
              flags = SEC_HAS_CONTENTS;
              break;
+           case readonly_section:
+             flags |= SEC_READONLY;
+             break;
+           case typed_readonly_section:
+             flags |= SEC_READONLY;
+             /* Fall through.  */
+           case type_section:
+             if (os->sectype_value->type.node_class == etree_name
+                 && os->sectype_value->type.node_code == NAME)
+               {
+                 const char *name = os->sectype_value->name.name;
+                 if (strcmp (name, "SHT_PROGBITS") == 0)
+                   type = SHT_PROGBITS;
+                 else if (strcmp (name, "SHT_STRTAB") == 0)
+                   type = SHT_STRTAB;
+                 else if (strcmp (name, "SHT_NOTE") == 0)
+                   type = SHT_NOTE;
+                 else if (strcmp (name, "SHT_NOBITS") == 0)
+                   type = SHT_NOBITS;
+                 else if (strcmp (name, "SHT_INIT_ARRAY") == 0)
+                   type = SHT_INIT_ARRAY;
+                 else if (strcmp (name, "SHT_FINI_ARRAY") == 0)
+                   type = SHT_FINI_ARRAY;
+                 else if (strcmp (name, "SHT_PREINIT_ARRAY") == 0)
+                   type = SHT_PREINIT_ARRAY;
+                 else
+                   einfo (_ ("%F%P: invalid type for output section `%s'\n"),
+                          os->name);
+               }
+            else
+              {
+                exp_fold_tree_no_dot (os->sectype_value);
+                if (expld.result.valid_p)
+                  type = expld.result.value;
+                else
+                  einfo (_ ("%F%P: invalid type for output section `%s'\n"),
+                         os->name);
+              }
+             break;
            case noload_section:
              if (bfd_get_flavour (link_info.output_bfd)
                  == bfd_target_elf_flavour)
@@ -4216,9 +4312,10 @@ map_input_to_output_sections
              break;
            }
          if (os->bfd_section == NULL)
-           init_os (os, flags);
+           init_os (os, flags | SEC_READONLY);
          else
            os->bfd_section->flags |= flags;
+         os->bfd_section->type = type;
          break;
        case lang_input_section_enum:
          break;
@@ -4259,7 +4356,7 @@ map_input_to_output_sections
                 place them in amongst other sections then the address
                 will affect following script sections, which is
                 likely to surprise naive users.  */
-             tos = lang_output_section_statement_lookup (name, 0, TRUE);
+             tos = lang_output_section_statement_lookup (name, 0, 1);
              tos->addr_tree = s->address_statement.address;
              if (tos->bfd_section == NULL)
                init_os (tos, 0);
@@ -4469,7 +4566,7 @@ strip_excluded_output_sections (void)
     {
       expld.phase = lang_mark_phase_enum;
       expld.dataseg.phase = exp_seg_none;
-      one_lang_size_sections_pass (NULL, FALSE);
+      one_lang_size_sections_pass (NULL, false);
       lang_reset_memory_regions ();
     }
 
@@ -4478,7 +4575,7 @@ strip_excluded_output_sections (void)
        os = os->next)
     {
       asection *output_section;
-      bfd_boolean exclude;
+      bool exclude;
 
       if (os->constraint < 0)
        continue;
@@ -4505,7 +4602,7 @@ strip_excluded_output_sections (void)
                && ((s->flags & SEC_LINKER_CREATED) != 0
                    || link_info.emitrelocations))
              {
-               exclude = FALSE;
+               exclude = false;
                break;
              }
        }
@@ -4515,7 +4612,7 @@ strip_excluded_output_sections (void)
          /* We don't set bfd_section to NULL since bfd_section of the
             removed output section statement may still be used.  */
          if (!os->update_dot)
-           os->ignored = TRUE;
+           os->ignored = true;
          output_section->flags |= SEC_EXCLUDE;
          bfd_section_list_remove (link_info.output_bfd, output_section);
          link_info.output_bfd->section_count--;
@@ -4554,7 +4651,7 @@ lang_clear_os_map (void)
 
   /* Stop future calls to lang_add_section from messing with map_head
      and map_tail link_order fields.  */
-  map_head_is_link_order = TRUE;
+  map_head_is_link_order = true;
 }
 
 static void
@@ -4606,7 +4703,7 @@ print_assignment (lang_assignment_statement_type *assignment,
                  lang_output_section_statement_type *output_section)
 {
   unsigned int i;
-  bfd_boolean is_dot;
+  bool is_dot;
   etree_type *tree;
   asection *osec;
 
@@ -4615,7 +4712,7 @@ print_assignment (lang_assignment_statement_type *assignment,
 
   if (assignment->exp->type.node_class == etree_assert)
     {
-      is_dot = FALSE;
+      is_dot = false;
       tree = assignment->exp->assert_s.child;
     }
   else
@@ -4633,7 +4730,7 @@ print_assignment (lang_assignment_statement_type *assignment,
   if (assignment->exp->type.node_class != etree_provide)
     exp_fold_tree (tree, osec, &print_dot);
   else
-    expld.result.valid_p = FALSE;
+    expld.result.valid_p = false;
 
   if (expld.result.valid_p)
     {
@@ -4657,7 +4754,7 @@ print_assignment (lang_assignment_statement_type *assignment,
          struct bfd_link_hash_entry *h;
 
          h = bfd_link_hash_lookup (link_info.hash, assignment->exp->assign.dst,
-                                   FALSE, FALSE, TRUE);
+                                   false, false, true);
          if (h != NULL
              && (h->type == bfd_link_hash_defined
                  || h->type == bfd_link_hash_defweak))
@@ -4699,7 +4796,7 @@ print_input_statement (lang_input_statement_type *statm)
 /* Print all symbols defined in a particular section.  This is called
    via bfd_link_hash_traverse, or by print_all_symbols.  */
 
-bfd_boolean
+bool
 print_one_symbol (struct bfd_link_hash_entry *hash_entry, void *ptr)
 {
   asection *sec = (asection *) ptr;
@@ -4720,7 +4817,7 @@ print_one_symbol (struct bfd_link_hash_entry *hash_entry, void *ptr)
       minfo ("             %pT\n", hash_entry->root.string);
     }
 
-  return TRUE;
+  return true;
 }
 
 static int
@@ -4771,7 +4868,7 @@ print_all_symbols (asection *sec)
 /* Print information about an input section to the map file.  */
 
 static void
-print_input_section (asection *i, bfd_boolean is_discarded)
+print_input_section (asection *i, bool is_discarded)
 {
   bfd_size_type size = i->size;
   int len;
@@ -5143,7 +5240,7 @@ print_statement (lang_statement_union_type *s,
       print_reloc_statement (&s->reloc_statement);
       break;
     case lang_input_section_enum:
-      print_input_section (s->input_section.section, FALSE);
+      print_input_section (s->input_section.section, false);
       break;
     case lang_padding_statement_enum:
       print_padding_statement (&s->padding_statement);
@@ -5260,7 +5357,7 @@ size_input_section
   (lang_statement_union_type **this_ptr,
    lang_output_section_statement_type *output_section_statement,
    fill_type *fill,
-   bfd_boolean *removed,
+   bool *removed,
    bfd_vma dot)
 {
   lang_input_section_type *is = &((*this_ptr)->input_section);
@@ -5365,7 +5462,7 @@ size_input_section
 struct check_sec
 {
   asection *sec;
-  bfd_boolean warned;
+  bool warned;
 };
 
 static int
@@ -5427,7 +5524,7 @@ lang_check_section_addresses (void)
   bfd_vma p_start = 0;
   bfd_vma p_end = 0;
   lang_memory_region_type *m;
-  bfd_boolean overlays;
+  bool overlays;
 
   /* Detect address space overflow on allocated sections.  */
   addr_mask = ((bfd_vma) 1 <<
@@ -5464,7 +5561,7 @@ lang_check_section_addresses (void)
        continue;
 
       sections[count].sec = s;
-      sections[count].warned = FALSE;
+      sections[count].warned = false;
       count++;
     }
 
@@ -5499,7 +5596,7 @@ lang_check_section_addresses (void)
              einfo (_("%X%P: section %s LMA [%V,%V]"
                       " overlaps section %s LMA [%V,%V]\n"),
                     s->name, s_start, s_end, p->name, p_start, p_end);
-             sections[i].warned = TRUE;
+             sections[i].warned = true;
            }
          p = s;
          p_start = s_start;
@@ -5513,14 +5610,14 @@ lang_check_section_addresses (void)
      this property.  It is possible to intentionally generate overlays
      that fail this test, but it would be unusual.  */
   qsort (sections, count, sizeof (*sections), sort_sections_by_vma);
-  overlays = FALSE;
+  overlays = false;
   p_start = sections[0].sec->vma;
   for (i = 1; i < count; i++)
     {
       s_start = sections[i].sec->vma;
       if (p_start == s_start)
        {
-         overlays = TRUE;
+         overlays = true;
          break;
        }
       p_start = s_start;
@@ -5597,7 +5694,7 @@ os_region_check (lang_output_section_statement_type *os,
        }
       else if (!region->had_full_message)
        {
-         region->had_full_message = TRUE;
+         region->had_full_message = true;
 
          einfo (_("%X%P: %pB section `%s' will not fit in region `%s'\n"),
                 os->bfd_section->owner,
@@ -5608,9 +5705,10 @@ os_region_check (lang_output_section_statement_type *os,
 }
 
 static void
-ldlang_check_relro_region (lang_statement_union_type *s,
-                          seg_align_type *seg)
+ldlang_check_relro_region (lang_statement_union_type *s)
 {
+  seg_align_type *seg = &expld.dataseg;
+
   if (seg->relro == exp_seg_relro_start)
     {
       if (!seg->relro_start_stat)
@@ -5639,17 +5737,17 @@ lang_size_sections_1
    lang_output_section_statement_type *output_section_statement,
    fill_type *fill,
    bfd_vma dot,
-   bfd_boolean *relax,
-   bfd_boolean check_regions)
+   bool *relax,
+   bool check_regions)
 {
   lang_statement_union_type *s;
   lang_statement_union_type *prev_s = NULL;
-  bfd_boolean removed_prev_s = FALSE;
+  bool removed_prev_s = false;
 
   /* Size up the sections from their constituent parts.  */
   for (s = *prev; s != NULL; prev_s = s, s = s->header.next)
     {
-      bfd_boolean removed=FALSE;
+      bool removed = false;
 
       switch (s->header.type)
        {
@@ -5675,7 +5773,7 @@ lang_size_sections_1
              os->addr_tree = exp_intop (0);
            if (os->addr_tree != NULL)
              {
-               os->processed_vma = FALSE;
+               os->processed_vma = false;
                exp_fold_tree (os->addr_tree, bfd_abs_section_ptr, &dot);
 
                if (expld.result.valid_p)
@@ -5819,7 +5917,7 @@ lang_size_sections_1
            lang_size_sections_1 (&os->children.head, os,
                                  os->fill, newdot, relax, check_regions);
 
-           os->processed_vma = TRUE;
+           os->processed_vma = true;
 
            if (bfd_is_abs_section (os->bfd_section) || os->ignored)
              /* Except for some special linker created sections,
@@ -5847,7 +5945,7 @@ lang_size_sections_1
            /* Set section lma.  */
            r = os->region;
            if (r == NULL)
-             r = lang_memory_region_lookup (DEFAULT_MEMORY_REGION, FALSE);
+             r = lang_memory_region_lookup (DEFAULT_MEMORY_REGION, false);
 
            if (os->load_base)
              {
@@ -5918,7 +6016,7 @@ lang_size_sections_1
                    os->bfd_section->lma = lma;
                  }
              }
-           os->processed_lma = TRUE;
+           os->processed_lma = true;
 
            /* Keep track of normal sections using the default
               lma region.  We use this to set the lma for
@@ -6076,12 +6174,12 @@ lang_size_sections_1
            i = s->input_section.section;
            if (relax)
              {
-               bfd_boolean again;
+               bool again;
 
                if (!bfd_relax_section (i->owner, i, &link_info, &again))
                  einfo (_("%F%P: can't relax section: %E\n"));
                if (again)
-                 *relax = TRUE;
+                 *relax = true;
              }
            dot = size_input_section (prev, output_section_statement,
                                      fill, &removed, dot);
@@ -6109,7 +6207,7 @@ lang_size_sections_1
                           output_section_statement->bfd_section,
                           &newdot);
 
-           ldlang_check_relro_region (s, &expld.dataseg);
+           ldlang_check_relro_region (s);
 
            expld.dataseg.relro = exp_seg_relro_none;
 
@@ -6127,7 +6225,7 @@ lang_size_sections_1
                    /* If we don't have an output section, then just adjust
                       the default memory address.  */
                    lang_memory_region_lookup (DEFAULT_MEMORY_REGION,
-                                              FALSE)->current = newdot;
+                                              false)->current = newdot;
                  }
                else if (newdot != dot)
                  {
@@ -6207,13 +6305,13 @@ lang_size_sections_1
                 the current one.  */
              prev_s->header.next=s->header.next;
              s = prev_s;
-             removed_prev_s = FALSE;
+             removed_prev_s = false;
            }
          else
            {
              /* Remove the first input section of the list.  */
              *prev = s->header.next;
-             removed_prev_s = TRUE;
+             removed_prev_s = true;
            }
 
          /* Move to next element, unless we removed the head of the
@@ -6224,7 +6322,7 @@ lang_size_sections_1
       else
        {
          prev = &s->header.next;
-         removed_prev_s = FALSE;
+         removed_prev_s = false;
        }
     }
   return dot;
@@ -6235,12 +6333,12 @@ lang_size_sections_1
    CURRENT_SECTION and PREVIOUS_SECTION ought to be placed into different
    segments.  We are allowed an opportunity to override this decision.  */
 
-bfd_boolean
+bool
 ldlang_override_segment_assignment (struct bfd_link_info *info ATTRIBUTE_UNUSED,
                                    bfd *abfd ATTRIBUTE_UNUSED,
                                    asection *current_section,
                                    asection *previous_section,
-                                   bfd_boolean new_segment)
+                                   bool new_segment)
 {
   lang_output_section_statement_type *cur;
   lang_output_section_statement_type *prev;
@@ -6248,7 +6346,7 @@ ldlang_override_segment_assignment (struct bfd_link_info *info ATTRIBUTE_UNUSED,
   /* The checks below are only necessary when the BFD library has decided
      that the two sections ought to be placed into the same segment.  */
   if (new_segment)
-    return TRUE;
+    return true;
 
   /* Paranoia checks.  */
   if (current_section == NULL || previous_section == NULL)
@@ -6258,7 +6356,7 @@ ldlang_override_segment_assignment (struct bfd_link_info *info ATTRIBUTE_UNUSED,
      sections comingled in the same segment.  */
   if (config.separate_code
       && ((current_section->flags ^ previous_section->flags) & SEC_CODE))
-    return TRUE;
+    return true;
 
   /* Find the memory regions associated with the two sections.
      We call lang_output_section_find() here rather than scanning the list
@@ -6279,7 +6377,7 @@ ldlang_override_segment_assignment (struct bfd_link_info *info ATTRIBUTE_UNUSED,
 }
 
 void
-one_lang_size_sections_pass (bfd_boolean *relax, bfd_boolean check_regions)
+one_lang_size_sections_pass (bool *relax, bool check_regions)
 {
   lang_statement_iteration++;
   if (expld.phase != lang_mark_phase_enum)
@@ -6288,37 +6386,38 @@ one_lang_size_sections_pass (bfd_boolean *relax, bfd_boolean check_regions)
                        0, 0, relax, check_regions);
 }
 
-static bfd_boolean
-lang_size_segment (seg_align_type *seg)
+static bool
+lang_size_segment (void)
 {
   /* If XXX_SEGMENT_ALIGN XXX_SEGMENT_END pair was seen, check whether
      a page could be saved in the data segment.  */
+  seg_align_type *seg = &expld.dataseg;
   bfd_vma first, last;
 
-  first = -seg->base & (seg->pagesize - 1);
-  last = seg->end & (seg->pagesize - 1);
+  first = -seg->base & (seg->commonpagesize - 1);
+  last = seg->end & (seg->commonpagesize - 1);
   if (first && last
-      && ((seg->base & ~(seg->pagesize - 1))
-         != (seg->end & ~(seg->pagesize - 1)))
-      && first + last <= seg->pagesize)
+      && ((seg->base & ~(seg->commonpagesize - 1))
+         != (seg->end & ~(seg->commonpagesize - 1)))
+      && first + last <= seg->commonpagesize)
     {
       seg->phase = exp_seg_adjust;
-      return TRUE;
+      return true;
     }
 
   seg->phase = exp_seg_done;
-  return FALSE;
+  return false;
 }
 
 static bfd_vma
-lang_size_relro_segment_1 (seg_align_type *seg)
+lang_size_relro_segment_1 (void)
 {
+  seg_align_type *seg = &expld.dataseg;
   bfd_vma relro_end, desired_end;
   asection *sec;
 
   /* Compute the expected PT_GNU_RELRO/PT_LOAD segment end.  */
-  relro_end = ((seg->relro_end + seg->pagesize - 1)
-              & ~(seg->pagesize - 1));
+  relro_end = (seg->relro_end + seg->relropagesize - 1) & -seg->relropagesize;
 
   /* Adjust by the offset arg of XXX_SEGMENT_RELRO_END.  */
   desired_end = relro_end - seg->relro_offset;
@@ -6351,47 +6450,35 @@ lang_size_relro_segment_1 (seg_align_type *seg)
   return relro_end;
 }
 
-static bfd_boolean
-lang_size_relro_segment (bfd_boolean *relax, bfd_boolean check_regions)
+static bool
+lang_size_relro_segment (bool *relax, bool check_regions)
 {
-  bfd_boolean do_reset = FALSE;
-  bfd_boolean do_data_relro;
-  bfd_vma data_initial_base, data_relro_end;
+  bool do_reset = false;
 
   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;
-    }
+      bfd_vma data_initial_base = expld.dataseg.base;
+      bfd_vma data_relro_end = lang_size_relro_segment_1 ();
 
-  if (do_data_relro)
-    {
       lang_reset_memory_regions ();
       one_lang_size_sections_pass (relax, check_regions);
 
       /* 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)
+      if (expld.dataseg.relro_end > data_relro_end)
        {
-         expld.dataseg.base = data_initial_base;;
-         do_reset = TRUE;
+         expld.dataseg.base = data_initial_base;
+         do_reset = true;
        }
     }
-
-  if (!do_data_relro && lang_size_segment (&expld.dataseg))
-    do_reset = TRUE;
+  else if (lang_size_segment ())
+    do_reset = true;
 
   return do_reset;
 }
 
 void
-lang_size_sections (bfd_boolean *relax, bfd_boolean check_regions)
+lang_size_sections (bool *relax, bool check_regions)
 {
   expld.phase = lang_allocating_phase_enum;
   expld.dataseg.phase = exp_seg_none;
@@ -6403,7 +6490,7 @@ lang_size_sections (bfd_boolean *relax, bfd_boolean check_regions)
 
   if (expld.dataseg.phase == exp_seg_end_seen)
     {
-      bfd_boolean do_reset
+      bool do_reset
        = lang_size_relro_segment (relax, check_regions);
 
       if (do_reset)
@@ -6422,7 +6509,7 @@ lang_size_sections (bfd_boolean *relax, bfd_boolean check_regions)
 
 static lang_output_section_statement_type *current_section;
 static lang_assignment_statement_type *current_assign;
-static bfd_boolean prefer_next_section;
+static bool prefer_next_section;
 
 /* Worker function for lang_do_assignments.  Recursiveness goes here.  */
 
@@ -6431,7 +6518,7 @@ lang_do_assignments_1 (lang_statement_union_type *s,
                       lang_output_section_statement_type *current_os,
                       fill_type *fill,
                       bfd_vma dot,
-                      bfd_boolean *found_end)
+                      bool *found_end)
 {
   for (; s != NULL; s = s->header.next)
     {
@@ -6450,32 +6537,34 @@ lang_do_assignments_1 (lang_statement_union_type *s,
            os = &(s->output_section_statement);
            os->after_end = *found_end;
            init_opb (os->bfd_section);
-           if (os->bfd_section != NULL && !os->ignored)
+           newdot = dot;
+           if (os->bfd_section != NULL)
              {
-               if ((os->bfd_section->flags & SEC_ALLOC) != 0)
+               if (!os->ignored && (os->bfd_section->flags & SEC_ALLOC) != 0)
                  {
                    current_section = os;
-                   prefer_next_section = FALSE;
+                   prefer_next_section = false;
                  }
-               dot = os->bfd_section->vma;
+               newdot = os->bfd_section->vma;
              }
            newdot = lang_do_assignments_1 (os->children.head,
-                                           os, os->fill, dot, found_end);
+                                           os, os->fill, newdot, found_end);
            if (!os->ignored)
              {
                if (os->bfd_section != NULL)
                  {
+                   newdot = os->bfd_section->vma;
+
                    /* .tbss sections effectively have zero size.  */
                    if (!IS_TBSS (os->bfd_section)
                        || bfd_link_relocatable (&link_info))
-                     dot += TO_ADDR (os->bfd_section->size);
+                     newdot += TO_ADDR (os->bfd_section->size);
 
                    if (os->update_dot_tree != NULL)
                      exp_fold_tree (os->update_dot_tree,
-                                    bfd_abs_section_ptr, &dot);
+                                    bfd_abs_section_ptr, &newdot);
                  }
-               else
-                 dot = newdot;
+               dot = newdot;
              }
          }
          break;
@@ -6560,12 +6649,12 @@ lang_do_assignments_1 (lang_statement_union_type *s,
              const char *p = current_assign->exp->assign.dst;
 
              if (current_os == abs_output_section && p[0] == '.' && p[1] == 0)
-               prefer_next_section = TRUE;
+               prefer_next_section = true;
 
              while (*p == '_')
                ++p;
              if (strcmp (p, "end") == 0)
-               *found_end = TRUE;
+               *found_end = true;
            }
          exp_fold_tree (s->assignment_statement.exp,
                         (current_os->bfd_section != NULL
@@ -6599,10 +6688,10 @@ lang_do_assignments_1 (lang_statement_union_type *s,
 void
 lang_do_assignments (lang_phase_type phase)
 {
-  bfd_boolean found_end = FALSE;
+  bool found_end = false;
 
   current_section = NULL;
-  prefer_next_section = FALSE;
+  prefer_next_section = false;
   expld.phase = phase;
   lang_statement_iteration++;
   lang_do_assignments_1 (statement_list.head,
@@ -6797,6 +6886,19 @@ undef_start_stop (struct bfd_link_hash_entry *h)
        }
       h->type = bfd_link_hash_undefined;
       h->u.undef.abfd = NULL;
+      if (is_elf_hash_table (link_info.hash))
+       {
+         const struct elf_backend_data *bed;
+         struct elf_link_hash_entry *eh = (struct elf_link_hash_entry *) h;
+         unsigned int was_forced = eh->forced_local;
+
+         bed = get_elf_backend_data (link_info.output_bfd);
+         (*bed->elf_backend_hide_symbol) (&link_info, eh, true);
+         if (!eh->ref_regular_nonweak)
+           h->type = bfd_link_hash_undefweak;
+         eh->def_regular = 0;
+         eh->forced_local = was_forced;
+       }
     }
 }
 
@@ -6869,17 +6971,55 @@ lang_finalize_start_stop (void)
   foreach_start_stop (set_start_stop);
 }
 
+static void
+lang_symbol_tweaks (void)
+{
+  /* 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.  */
+  if (config.build_constructors)
+    lang_init_start_stop ();
+
+  /* Make __ehdr_start hidden, and set def_regular even though it is
+     likely undefined at this stage.  For lang_check_relocs.  */
+  if (is_elf_hash_table (link_info.hash)
+      && !bfd_link_relocatable (&link_info))
+    {
+      struct elf_link_hash_entry *h = (struct elf_link_hash_entry *)
+       bfd_link_hash_lookup (link_info.hash, "__ehdr_start",
+                             false, false, true);
+
+      /* Only adjust the export class if the symbol was referenced
+        and not defined, otherwise leave it alone.  */
+      if (h != NULL
+         && (h->root.type == bfd_link_hash_new
+             || h->root.type == bfd_link_hash_undefined
+             || h->root.type == bfd_link_hash_undefweak
+             || h->root.type == bfd_link_hash_common))
+       {
+         const struct elf_backend_data *bed;
+         bed = get_elf_backend_data (link_info.output_bfd);
+         (*bed->elf_backend_hide_symbol) (&link_info, h, true);
+         if (ELF_ST_VISIBILITY (h->other) != STV_INTERNAL)
+           h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN;
+         h->def_regular = 1;
+         h->root.linker_def = 1;
+         h->root.rel_from_abs = 1;
+       }
+    }
+}
+
 static void
 lang_end (void)
 {
   struct bfd_link_hash_entry *h;
-  bfd_boolean warn;
+  bool warn;
 
   if ((bfd_link_relocatable (&link_info) && !link_info.gc_sections)
       || bfd_link_dll (&link_info))
     warn = entry_from_cmdline;
   else
-    warn = TRUE;
+    warn = true;
 
   /* Force the user to specify a root when generating a relocatable with
      --gc-sections, unless --gc-keep-exported was also given.  */
@@ -6892,7 +7032,7 @@ lang_end (void)
       for (sym = link_info.gc_sym_list; sym != NULL; sym = sym->next)
        {
          h = bfd_link_hash_lookup (link_info.hash, sym->name,
-                                   FALSE, FALSE, FALSE);
+                                   false, false, false);
          if (h != NULL
              && (h->type == bfd_link_hash_defined
                  || h->type == bfd_link_hash_defweak)
@@ -6909,11 +7049,11 @@ lang_end (void)
       /* No entry has been specified.  Look for the default entry, but
         don't warn if we don't find it.  */
       entry_symbol.name = entry_symbol_default;
-      warn = FALSE;
+      warn = false;
     }
 
   h = bfd_link_hash_lookup (link_info.hash, entry_symbol.name,
-                           FALSE, FALSE, TRUE);
+                           false, false, true);
   if (h != NULL
       && (h->type == bfd_link_hash_defined
          || h->type == bfd_link_hash_defweak)
@@ -6940,7 +7080,8 @@ lang_end (void)
          if (!bfd_set_start_address (link_info.output_bfd, val))
            einfo (_("%F%P: can't set start address\n"));
        }
-      else
+      /* BZ 2004952: Only use the start of the entry section for executables.  */
+      else if bfd_link_executable (&link_info)
        {
          asection *ts;
 
@@ -6966,6 +7107,13 @@ lang_end (void)
                       entry_symbol.name);
            }
        }
+      else
+       {
+         if (warn)
+           einfo (_("%P: warning: cannot find entry symbol %s;"
+                    " not setting start address\n"),
+                  entry_symbol.name);
+       }
     }
 }
 
@@ -7101,7 +7249,7 @@ lang_common (void)
 
 /* Place one common symbol in the correct section.  */
 
-static bfd_boolean
+static bool
 lang_one_common (struct bfd_link_hash_entry *h, void *info)
 {
   unsigned int power_of_two;
@@ -7109,17 +7257,17 @@ lang_one_common (struct bfd_link_hash_entry *h, void *info)
   asection *section;
 
   if (h->type != bfd_link_hash_common)
-    return TRUE;
+    return true;
 
   size = h->u.c.size;
   power_of_two = h->u.c.p->alignment_power;
 
   if (config.sort_common == sort_descending
       && power_of_two < *(unsigned int *) info)
-    return TRUE;
+    return true;
   else if (config.sort_common == sort_ascending
           && power_of_two > *(unsigned int *) info)
-    return TRUE;
+    return true;
 
   section = h->u.c.p->section;
   if (!bfd_define_common_symbol (link_info.output_bfd, &link_info, h))
@@ -7128,7 +7276,7 @@ lang_one_common (struct bfd_link_hash_entry *h, void *info)
 
   if (config.map_file != NULL)
     {
-      static bfd_boolean header_printed;
+      static bool header_printed;
       int len;
       char *name;
       char buf[50];
@@ -7137,7 +7285,7 @@ lang_one_common (struct bfd_link_hash_entry *h, void *info)
        {
          minfo (_("\nAllocating common symbols\n"));
          minfo (_("Common symbol       size              file\n\n"));
-         header_printed = TRUE;
+         header_printed = true;
        }
 
       name = bfd_demangle (link_info.output_bfd, h->root.string,
@@ -7182,7 +7330,7 @@ lang_one_common (struct bfd_link_hash_entry *h, void *info)
       minfo ("%pB\n", section->owner);
     }
 
-  return TRUE;
+  return true;
 }
 
 /* Handle a single orphan section S, placing the orphan into an appropriate
@@ -7195,13 +7343,12 @@ ldlang_place_orphan (asection *s)
   if (config.orphan_handling == orphan_handling_discard)
     {
       lang_output_section_statement_type *os;
-      os = lang_output_section_statement_lookup (DISCARD_SECTION_NAME, 0,
-                                                TRUE);
+      os = lang_output_section_statement_lookup (DISCARD_SECTION_NAME, 0, 1);
       if (os->addr_tree == NULL
          && (bfd_link_relocatable (&link_info)
              || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0))
        os->addr_tree = exp_intop (0);
-      lang_add_section (&os->children, s, NULL, os);
+      lang_add_section (&os->children, s, NULL, NULL, os);
     }
   else
     {
@@ -7219,12 +7366,12 @@ ldlang_place_orphan (asection *s)
       os = ldemul_place_orphan (s, name, constraint);
       if (os == NULL)
        {
-         os = lang_output_section_statement_lookup (name, constraint, TRUE);
+         os = lang_output_section_statement_lookup (name, constraint, 1);
          if (os->addr_tree == NULL
              && (bfd_link_relocatable (&link_info)
                  || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0))
            os->addr_tree = exp_intop (0);
-         lang_add_section (&os->children, s, NULL, os);
+         lang_add_section (&os->children, s, NULL, NULL, os);
        }
 
       if (config.orphan_handling == orphan_handling_warn)
@@ -7266,10 +7413,9 @@ lang_place_orphans (void)
                    {
                      if (default_common_section == NULL)
                        default_common_section
-                         = lang_output_section_statement_lookup (".bss", 0,
-                                                                 TRUE);
+                         = lang_output_section_statement_lookup (".bss", 0, 1);
                      lang_add_section (&default_common_section->children, s,
-                                       NULL, default_common_section);
+                                       NULL, NULL, default_common_section);
                    }
                }
              else
@@ -7392,7 +7538,7 @@ lang_add_output (const char *name, int from_script)
   if (!had_output_filename || !from_script)
     {
       output_filename = name;
-      had_output_filename = TRUE;
+      had_output_filename = true;
     }
 }
 
@@ -7400,6 +7546,7 @@ lang_output_section_statement_type *
 lang_enter_output_section_statement (const char *output_section_statement_name,
                                     etree_type *address_exp,
                                     enum section_type sectype,
+                                    etree_type *sectype_value,
                                     etree_type *align,
                                     etree_type *subalign,
                                     etree_type *ebase,
@@ -7409,7 +7556,7 @@ lang_enter_output_section_statement (const char *output_section_statement_name,
   lang_output_section_statement_type *os;
 
   os = lang_output_section_statement_lookup (output_section_statement_name,
-                                            constraint, TRUE);
+                                            constraint, 2);
   current_section = os;
 
   if (os->addr_tree == NULL)
@@ -7417,10 +7564,12 @@ lang_enter_output_section_statement (const char *output_section_statement_name,
       os->addr_tree = address_exp;
     }
   os->sectype = sectype;
-  if (sectype != noload_section)
-    os->flags = SEC_NO_FLAGS;
-  else
+  if (sectype == type_section || sectype == typed_readonly_section)
+    os->sectype_value = sectype_value;
+  else if (sectype == noload_section)
     os->flags = SEC_NEVER_LOAD;
+  else
+    os->flags = SEC_NO_FLAGS;
   os->block_value = 1;
 
   /* Make next things chain into subchain of this.  */
@@ -7466,8 +7615,8 @@ lang_reset_memory_regions (void)
        os != NULL;
        os = os->next)
     {
-      os->processed_vma = FALSE;
-      os->processed_lma = FALSE;
+      os->processed_vma = false;
+      os->processed_lma = false;
     }
 
   for (o = link_info.output_bfd->sections; o != NULL; o = o->next)
@@ -7485,7 +7634,6 @@ static void
 gc_section_callback (lang_wild_statement_type *ptr,
                     struct wildcard_list *sec ATTRIBUTE_UNUSED,
                     asection *section,
-                    struct flag_info *sflag_info ATTRIBUTE_UNUSED,
                     lang_input_statement_type *file ATTRIBUTE_UNUSED,
                     void *data ATTRIBUTE_UNUSED)
 {
@@ -7529,7 +7677,7 @@ lang_gc_sections (void)
   lang_gc_sections_1 (statement_list.head);
 
   /* SEC_EXCLUDE is ignored when doing a relocatable link, except in
-     the special case of debug info.  (See bfd/stabs.c)
+     the special case of .stabstr debug info.  (See bfd/stabs.c)
      Twiddle the flag here, to simplify later linker code.  */
   if (bfd_link_relocatable (&link_info))
     {
@@ -7541,7 +7689,8 @@ lang_gc_sections (void)
            continue;
 #endif
          for (sec = f->the_bfd->sections; sec != NULL; sec = sec->next)
-           if ((sec->flags & SEC_DEBUGGING) == 0)
+           if ((sec->flags & SEC_DEBUGGING) == 0
+               || strcmp (sec->name, ".stabstr") != 0)
              sec->flags &= ~SEC_EXCLUDE;
        }
     }
@@ -7556,7 +7705,6 @@ static void
 find_relro_section_callback (lang_wild_statement_type *ptr ATTRIBUTE_UNUSED,
                             struct wildcard_list *sec ATTRIBUTE_UNUSED,
                             asection *section,
-                            struct flag_info *sflag_info ATTRIBUTE_UNUSED,
                             lang_input_statement_type *file ATTRIBUTE_UNUSED,
                             void *data)
 {
@@ -7568,8 +7716,8 @@ find_relro_section_callback (lang_wild_statement_type *ptr ATTRIBUTE_UNUSED,
       && !IGNORE_SECTION (section)
       && section->size != 0)
     {
-      bfd_boolean *has_relro_section = (bfd_boolean *) data;
-      *has_relro_section = TRUE;
+      bool *has_relro_section = (bool *) data;
+      *has_relro_section = true;
     }
 }
 
@@ -7577,15 +7725,14 @@ 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)
+                           bool *has_relro_section)
 {
   if (*has_relro_section)
     return;
 
   for (; s != NULL; s = s->header.next)
     {
-      if (s == seg->relro_end_stat)
+      if (s == expld.dataseg.relro_end_stat)
        break;
 
       switch (s->header.type)
@@ -7597,15 +7744,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,
-                                     seg, has_relro_section);
+                                     has_relro_section);
          break;
        case lang_output_section_statement_enum:
          lang_find_relro_sections_1 (s->output_section_statement.children.head,
-                                     seg, has_relro_section);
+                                     has_relro_section);
          break;
        case lang_group_statement_enum:
          lang_find_relro_sections_1 (s->group_statement.children.head,
-                                     seg, has_relro_section);
+                                     has_relro_section);
          break;
        default:
          break;
@@ -7616,23 +7763,24 @@ lang_find_relro_sections_1 (lang_statement_union_type *s,
 static void
 lang_find_relro_sections (void)
 {
-  bfd_boolean has_relro_section = FALSE;
+  bool has_relro_section = false;
 
   /* Check all sections in the link script.  */
 
   lang_find_relro_sections_1 (expld.dataseg.relro_start_stat,
-                             &expld.dataseg, &has_relro_section);
+                             &has_relro_section);
 
   if (!has_relro_section)
-    link_info.relro = FALSE;
+    link_info.relro = false;
 }
 
 /* Relax all sections until bfd_relax_section gives up.  */
 
 void
-lang_relax_sections (bfd_boolean need_layout)
+lang_relax_sections (bool need_layout)
 {
-  if (RELAXATION_ENABLED)
+  /* NB: Also enable relaxation to layout sections for DT_RELR.  */
+  if (RELAXATION_ENABLED || link_info.enable_dt_relr)
     {
       /* We may need more than one relaxation pass.  */
       int i = link_info.relax_pass;
@@ -7643,7 +7791,7 @@ lang_relax_sections (bfd_boolean need_layout)
       while (i--)
        {
          /* Keep relaxing until bfd_relax_section gives up.  */
-         bfd_boolean relax_again;
+         bool relax_again;
 
          link_info.relax_trip = -1;
          do
@@ -7664,14 +7812,14 @@ lang_relax_sections (bfd_boolean need_layout)
 
              /* Perform another relax pass - this time we know where the
                 globals are, so can make a better guess.  */
-             relax_again = FALSE;
-             lang_size_sections (&relax_again, FALSE);
+             relax_again = false;
+             lang_size_sections (&relax_again, false);
            }
          while (relax_again);
 
          link_info.relax_pass++;
        }
-      need_layout = TRUE;
+      need_layout = true;
     }
 
   if (need_layout)
@@ -7679,7 +7827,7 @@ lang_relax_sections (bfd_boolean need_layout)
       /* Final extra sizing to report errors.  */
       lang_do_assignments (lang_assigning_phase_enum);
       lang_reset_memory_regions ();
-      lang_size_sections (NULL, TRUE);
+      lang_size_sections (NULL, true);
     }
 }
 
@@ -7696,7 +7844,7 @@ lang_relax_sections (bfd_boolean need_layout)
    inserted at the head of the file_chain.  */
 
 static lang_input_statement_type *
-find_replacements_insert_point (bfd_boolean *before)
+find_replacements_insert_point (bool *before)
 {
   lang_input_statement_type *claim1, *lastobject;
   lastobject = (void *) input_file_chain.head;
@@ -7716,7 +7864,7 @@ find_replacements_insert_point (bfd_boolean *before)
   /* No files were claimed by the plugin.  Choose the last object
      file found on the list (maybe the first, dummy entry) as the
      insert point.  */
-  *before = FALSE;
+  *before = false;
   return lastobject;
 }
 
@@ -7859,7 +8007,7 @@ lang_check_relocs (void)
        if (!bfd_link_check_relocs (abfd, &link_info))
          {
            /* No object output, fail return.  */
-           config.make_executable = FALSE;
+           config.make_executable = false;
            /* Note: we do not abort the loop, but rather
               continue the scan in case there are other
               bad relocations to report.  */
@@ -7915,7 +8063,7 @@ lang_process (void)
      means that when we call open_input_bfds PROVIDE statements will
      trigger to provide any needed symbols.  The regions origins and
      lengths are not assigned as a result of this call.  */
-  lang_do_memory_regions (FALSE);
+  lang_do_memory_regions (false);
 
   /* Create a bfd for each input file.  */
   current_target = default_target;
@@ -7924,7 +8072,7 @@ lang_process (void)
 
   /* Now that open_input_bfds has processed assignments and provide
      statements we can give values to symbolic origin/length now.  */
-  lang_do_memory_regions (TRUE);
+  lang_do_memory_regions (true);
 
 #if BFD_SUPPORTS_PLUGINS
   if (link_info.lto_plugin_active)
@@ -7945,7 +8093,7 @@ lang_process (void)
       if (plugin_call_all_symbols_read ())
        einfo (_("%F%P: %s: plugin reported error after all symbols read\n"),
               plugin_error_plugin ());
-      link_info.lto_all_symbols_read = TRUE;
+      link_info.lto_all_symbols_read = true;
       /* Open any newly added files, updating the file chains.  */
       plugin_undefs = link_info.hash->undefs_tail;
       open_input_bfds (*added.tail, OPEN_BFD_NORMAL);
@@ -7963,7 +8111,7 @@ lang_process (void)
             after the first input file that was claimed by the plugin,
             unless that file was an archive in which case it is inserted
             immediately before.  */
-         bfd_boolean before;
+         bool before;
          lang_statement_union_type **prev;
          plugin_insert = find_replacements_insert_point (&before);
          /* If a plugin adds input files without having claimed any, we
@@ -8079,11 +8227,7 @@ 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 ();
+  lang_symbol_tweaks ();
 
   /* PR 13683: We must rerun the assignments prior to running garbage
      collection in order to make sure that all symbol aliases are resolved.  */
@@ -8096,6 +8240,8 @@ lang_process (void)
   /* Remove unreferenced sections if asked to.  */
   lang_gc_sections ();
 
+  lang_mark_undefineds ();
+
   /* Check relocations.  */
   lang_check_relocs ();
 
@@ -8211,7 +8357,7 @@ lang_process (void)
 void
 lang_add_wild (struct wildcard_spec *filespec,
               struct wildcard_list *section_list,
-              bfd_boolean keep_sections)
+              bool keep_sections)
 {
   struct wildcard_list *curr, *next;
   lang_wild_statement_type *new_stmt;
@@ -8230,12 +8376,12 @@ lang_add_wild (struct wildcard_spec *filespec,
       if (strcmp (filespec->name, "*") == 0)
        filespec->name = NULL;
       else if (!wildcardp (filespec->name))
-       lang_has_input_file = TRUE;
+       lang_has_input_file = true;
     }
 
   new_stmt = new_stat (lang_wild_statement, stat_ptr);
   new_stmt->filename = NULL;
-  new_stmt->filenames_sorted = FALSE;
+  new_stmt->filenames_sorted = false;
   new_stmt->section_flag_list = NULL;
   new_stmt->exclude_name_list = NULL;
   if (filespec != NULL)
@@ -8269,7 +8415,7 @@ lang_section_start (const char *name, etree_type *address,
    precedence.  */
 
 void
-lang_add_entry (const char *name, bfd_boolean cmdline)
+lang_add_entry (const char *name, bool cmdline)
 {
   if (entry_symbol.name == NULL
       || cmdline
@@ -8307,7 +8453,7 @@ lang_add_map (const char *name)
       switch (*name)
        {
        case 'F':
-         map_option_f = TRUE;
+         map_option_f = true;
          break;
        }
       name++;
@@ -8385,11 +8531,11 @@ lang_startup (const char *name)
     }
   first_file->filename = name;
   first_file->local_sym_name = name;
-  first_file->flags.real = TRUE;
+  first_file->flags.real = true;
 }
 
 void
-lang_float (bfd_boolean maybe)
+lang_float (bool maybe)
 {
   lang_float_flag = maybe;
 }
@@ -8411,10 +8557,10 @@ lang_get_regions (lang_memory_region_type **region,
                  lang_memory_region_type **lma_region,
                  const char *memspec,
                  const char *lma_memspec,
-                 bfd_boolean have_lma,
-                 bfd_boolean have_vma)
+                 bool have_lma,
+                 bool have_vma)
 {
-  *lma_region = lang_memory_region_lookup (lma_memspec, FALSE);
+  *lma_region = lang_memory_region_lookup (lma_memspec, false);
 
   /* If no runtime region or VMA has been specified, but the load region
      has been specified, then use the load region for the runtime region
@@ -8424,7 +8570,7 @@ lang_get_regions (lang_memory_region_type **region,
       && strcmp (memspec, DEFAULT_MEMORY_REGION) == 0)
     *region = *lma_region;
   else
-    *region = lang_memory_region_lookup (memspec, FALSE);
+    *region = lang_memory_region_lookup (memspec, false);
 
   if (have_lma && lma_memspec != 0)
     einfo (_("%X%P:%pS: section has both a load address and a load region\n"),
@@ -8509,13 +8655,13 @@ lang_leave_group (void)
 void
 lang_new_phdr (const char *name,
               etree_type *type,
-              bfd_boolean filehdr,
-              bfd_boolean phdrs,
+              bool filehdr,
+              bool phdrs,
               etree_type *at,
               etree_type *flags)
 {
   struct lang_phdr *n, **pp;
-  bfd_boolean hdrs;
+  bool hdrs;
 
   n = stat_alloc (sizeof (struct lang_phdr));
   n->next = NULL;
@@ -8535,7 +8681,7 @@ lang_new_phdr (const char *name,
       {
        einfo (_("%X%P:%pS: PHDRS and FILEHDR are not supported"
                 " when prior PT_LOAD headers lack them\n"), NULL);
-       hdrs = FALSE;
+       hdrs = false;
       }
 
   *pp = n;
@@ -8626,7 +8772,7 @@ lang_record_phdrs (void)
                    }
                  secs[c] = os->bfd_section;
                  ++c;
-                 pl->used = TRUE;
+                 pl->used = true;
                }
            }
        }
@@ -8679,11 +8825,11 @@ lang_add_nocrossref (lang_nocrossref_type *l)
   n = (struct lang_nocrossrefs *) xmalloc (sizeof *n);
   n->next = nocrossref_list;
   n->list = l;
-  n->onlyfirst = FALSE;
+  n->onlyfirst = false;
   nocrossref_list = n;
 
   /* Set notice_all so that we get informed about all symbols.  */
-  link_info.notice_all = TRUE;
+  link_info.notice_all = true;
 }
 
 /* Record a section that cannot be referenced from a list of sections.  */
@@ -8692,7 +8838,7 @@ void
 lang_add_nocrossref_to (lang_nocrossref_type *l)
 {
   lang_add_nocrossref (l);
-  nocrossref_list->onlyfirst = TRUE;
+  nocrossref_list->onlyfirst = true;
 }
 \f
 /* Overlay handling.  We handle overlays with some static variables.  */
@@ -8739,7 +8885,7 @@ lang_enter_overlay_section (const char *name)
   etree_type *size;
 
   lang_enter_output_section_statement (name, overlay_vma, overlay_section,
-                                      0, overlay_subalign, 0, 0, 0);
+                                      0, 0, overlay_subalign, 0, 0, 0);
 
   /* If this is the first section, then base the VMA of future
      sections on this one.  This will work correctly even if `.' is
@@ -8795,7 +8941,7 @@ lang_leave_overlay_section (fill_type *fill,
   sprintf (buf, "__load_start_%s", clean);
   lang_add_assignment (exp_provide (buf,
                                    exp_nameop (LOADADDR, name),
-                                   FALSE));
+                                   false));
 
   buf = (char *) xmalloc (strlen (clean) + sizeof "__load_stop_");
   sprintf (buf, "__load_stop_%s", clean);
@@ -8803,7 +8949,7 @@ lang_leave_overlay_section (fill_type *fill,
                                    exp_binop ('+',
                                               exp_nameop (LOADADDR, name),
                                               exp_nameop (SIZEOF, name)),
-                                   FALSE));
+                                   false));
 
   free (clean);
 }
@@ -8826,7 +8972,7 @@ lang_leave_overlay (etree_type *lma_expr,
 
   lang_get_regions (&region, &lma_region,
                    memspec, lma_memspec,
-                   lma_expr != NULL, FALSE);
+                   lma_expr != NULL, false);
 
   nocrossref = NULL;
 
@@ -8836,7 +8982,7 @@ lang_leave_overlay (etree_type *lma_expr,
     {
       overlay_list->os->update_dot = 1;
       overlay_list->os->update_dot_tree
-       = exp_assign (".", exp_binop ('+', overlay_vma, overlay_max), FALSE);
+       = exp_assign (".", exp_binop ('+', overlay_vma, overlay_max), false);
     }
 
   l = overlay_list;
@@ -9016,7 +9162,7 @@ static const char *
 realsymbol (const char *pattern)
 {
   const char *p;
-  bfd_boolean changed = FALSE, backslash = FALSE;
+  bool changed = false, backslash = false;
   char *s, *symbol = (char *) xmalloc (strlen (pattern) + 1);
 
   for (p = pattern, s = symbol; *p != '\0'; ++p)
@@ -9027,8 +9173,8 @@ realsymbol (const char *pattern)
        {
          /* Remove the preceding backslash.  */
          *(s - 1) = *p;
-         backslash = FALSE;
-         changed = TRUE;
+         backslash = false;
+         changed = true;
        }
       else
        {
@@ -9063,7 +9209,7 @@ struct bfd_elf_version_expr *
 lang_new_vers_pattern (struct bfd_elf_version_expr *orig,
                       const char *new_name,
                       const char *lang,
-                      bfd_boolean literal_p)
+                      bool literal_p)
 {
   struct bfd_elf_version_expr *ret;
 
@@ -9071,12 +9217,12 @@ lang_new_vers_pattern (struct bfd_elf_version_expr *orig,
   ret->next = orig;
   ret->symver = 0;
   ret->script = 0;
-  ret->literal = TRUE;
+  ret->literal = true;
   ret->pattern = literal_p ? new_name : realsymbol (new_name);
   if (ret->pattern == NULL)
     {
       ret->pattern = new_name;
-      ret->literal = FALSE;
+      ret->literal = false;
     }
 
   if (lang == NULL || strcasecmp (lang, "C") == 0)
@@ -9367,7 +9513,7 @@ lang_do_version_exports_section (void)
       p = contents;
       while (p < contents + len)
        {
-         greg = lang_new_vers_pattern (greg, p, NULL, FALSE);
+         greg = lang_new_vers_pattern (greg, p, NULL, false);
          p = strchr (p, '\0') + 1;
        }
 
@@ -9377,7 +9523,7 @@ lang_do_version_exports_section (void)
       sec->flags |= SEC_EXCLUDE | SEC_KEEP;
     }
 
-  lreg = lang_new_vers_pattern (NULL, "*", NULL, FALSE);
+  lreg = lang_new_vers_pattern (NULL, "*", NULL, false);
   lang_register_vers_node (command_line.version_exports_section,
                           lang_new_vers_node (greg, lreg), NULL);
 }
@@ -9391,7 +9537,7 @@ lang_do_version_exports_section (void)
    data structures, and throw errors if missing symbols are encountered.  */
 
 static void
-lang_do_memory_regions (bfd_boolean update_regions_p)
+lang_do_memory_regions (bool update_regions_p)
 {
   lang_memory_region_type *r = lang_memory_region_list;
 
@@ -9483,7 +9629,7 @@ lang_append_dynamic_list_cpp_typeinfo (void)
 
   for (i = 0; i < ARRAY_SIZE (symbols); i++)
     dynamic = lang_new_vers_pattern (dynamic, symbols [i], "C++",
-                                    FALSE);
+                                    false);
 
   lang_append_dynamic_list (&link_info.dynamic_list, dynamic);
 }
@@ -9504,7 +9650,7 @@ lang_append_dynamic_list_cpp_new (void)
 
   for (i = 0; i < ARRAY_SIZE (symbols); i++)
     dynamic = lang_new_vers_pattern (dynamic, symbols [i], "C++",
-                                    FALSE);
+                                    false);
 
   lang_append_dynamic_list (&link_info.dynamic_list, dynamic);
 }
@@ -9530,7 +9676,7 @@ lang_ld_feature (char *str)
       sep = *q;
       *q = 0;
       if (strcasecmp (p, "SANE_EXPR") == 0)
-       config.sane_expr = TRUE;
+       config.sane_expr = true;
       else
        einfo (_("%X%P: unknown feature `%s'\n"), p);
       *q = sep;