oops - forgot to commit with the previous delta
[deliverable/binutils-gdb.git] / ld / ldlang.c
index 8d95254564f8a75bff9f7427f7456bc9f4d63d66..855e7951f4d86ed03445e3d692a05b0378619846 100644 (file)
@@ -193,7 +193,7 @@ input_statement_is_archive_path (const char *file_spec, char *sep,
   return match;
 }
 
-bfd_boolean
+static bfd_boolean
 unique_section_p (const asection *sec)
 {
   struct unique_sections *unam;
@@ -1149,7 +1149,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);
+    lang_output_section_statement_lookup (BFD_ABS_SECTION_NAME, 0, TRUE);
 
   abs_output_section->bfd_section = bfd_abs_section_ptr;
 
@@ -1255,44 +1255,19 @@ lang_memory_default (asection *section)
 }
 
 lang_output_section_statement_type *
-lang_output_section_find (const char *const name)
-{
-  struct out_section_hash_entry *entry;
-  unsigned long hash;
-
-  entry = ((struct out_section_hash_entry *)
-          bfd_hash_lookup (&output_section_statement_table, name,
-                           FALSE, FALSE));
-  if (entry == NULL)
-    return NULL;
-
-  hash = entry->root.hash;
-  do
-    {
-      if (entry->s.output_section_statement.constraint != -1)
-       return &entry->s.output_section_statement;
-      entry = (struct out_section_hash_entry *) entry->root.next;
-    }
-  while (entry != NULL
-        && entry->root.hash == hash
-        && strcmp (name, entry->s.output_section_statement.name) == 0);
-
-  return NULL;
-}
-
-static lang_output_section_statement_type *
-lang_output_section_statement_lookup_1 (const char *const name, int constraint)
+lang_output_section_statement_lookup (const char *const name,
+                                     int constraint,
+                                     bfd_boolean create)
 {
   struct out_section_hash_entry *entry;
-  struct out_section_hash_entry *last_ent;
-  unsigned long hash;
 
   entry = ((struct out_section_hash_entry *)
           bfd_hash_lookup (&output_section_statement_table, name,
-                           TRUE, FALSE));
+                           create, FALSE));
   if (entry == NULL)
     {
-      einfo (_("%P%F: failed creating section `%s': %E\n"), name);
+      if (create)
+       einfo (_("%P%F: failed creating section `%s': %E\n"), name);
       return NULL;
     }
 
@@ -1300,20 +1275,31 @@ lang_output_section_statement_lookup_1 (const char *const name, int constraint)
     {
       /* We have a section of this name, but it might not have the correct
         constraint.  */
-      hash = entry->root.hash;
-      do
-       {
-         if (entry->s.output_section_statement.constraint != -1
-             && (constraint == 0
-                 || (constraint == entry->s.output_section_statement.constraint
-                     && constraint != SPECIAL)))
-           return &entry->s.output_section_statement;
-         last_ent = entry;
-         entry = (struct out_section_hash_entry *) entry->root.next;
-       }
-      while (entry != NULL
-            && entry->root.hash == hash
-            && strcmp (name, entry->s.output_section_statement.name) == 0);
+      struct out_section_hash_entry *last_ent;
+      unsigned long hash = entry->root.hash;
+
+      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 (entry->s.output_section_statement.constraint >= 0
+               && (constraint == 0
+                   || (constraint
+                       == entry->s.output_section_statement.constraint)))
+             return &entry->s.output_section_statement;
+           last_ent = entry;
+           entry = (struct out_section_hash_entry *) entry->root.next;
+         }
+       while (entry != NULL
+              && entry->root.hash == hash
+              && strcmp (name, entry->s.output_section_statement.name) == 0);
+
+      if (!create)
+       return NULL;
 
       entry
        = ((struct out_section_hash_entry *)
@@ -1334,12 +1320,6 @@ lang_output_section_statement_lookup_1 (const char *const name, int constraint)
   return &entry->s.output_section_statement;
 }
 
-lang_output_section_statement_type *
-lang_output_section_statement_lookup (const char *const name)
-{
-  return lang_output_section_statement_lookup_1 (name, 0);
-}
-
 /* A variant of lang_output_section_find used by place_orphan.
    Returns the output statement that should precede a new output
    statement for SEC.  If an exact match is found on certain flags,
@@ -1383,7 +1363,8 @@ lang_output_section_find_by_flags (const asection *sec,
       return found;
     }
 
-  if (sec->flags & SEC_CODE)
+  if ((sec->flags & SEC_CODE) != 0
+      && (sec->flags & SEC_ALLOC) != 0)
     {
       /* Try for a rw code section.  */
       for (look = first; look; look = look->next)
@@ -1403,7 +1384,8 @@ lang_output_section_find_by_flags (const asection *sec,
            found = look;
        }
     }
-  else if (sec->flags & (SEC_READONLY | SEC_THREAD_LOCAL))
+  else if ((sec->flags & (SEC_READONLY | SEC_THREAD_LOCAL)) != 0
+          && (sec->flags & SEC_ALLOC) != 0)
     {
       /* .rodata can go after .text, .sdata2 after .rodata.  */
       for (look = first; look; look = look->next)
@@ -1424,7 +1406,8 @@ lang_output_section_find_by_flags (const asection *sec,
            found = look;
        }
     }
-  else if (sec->flags & SEC_SMALL_DATA)
+  else if ((sec->flags & SEC_SMALL_DATA) != 0
+          && (sec->flags & SEC_ALLOC) != 0)
     {
       /* .sdata goes after .data, .sbss after .sdata.  */
       for (look = first; look; look = look->next)
@@ -1446,7 +1429,8 @@ lang_output_section_find_by_flags (const asection *sec,
            found = look;
        }
     }
-  else if (sec->flags & SEC_HAS_CONTENTS)
+  else if ((sec->flags & SEC_HAS_CONTENTS) != 0
+          && (sec->flags & SEC_ALLOC) != 0)
     {
       /* .data goes after .rodata.  */
       for (look = first; look; look = look->next)
@@ -1466,9 +1450,9 @@ lang_output_section_find_by_flags (const asection *sec,
            found = look;
        }
     }
-  else
+  else if ((sec->flags & SEC_ALLOC) != 0)
     {
-      /* .bss goes last.  */
+      /* .bss goes after any other alloc section.  */
       for (look = first; look; look = look->next)
        {
          flags = look->flags;
@@ -1485,6 +1469,20 @@ lang_output_section_find_by_flags (const asection *sec,
            found = look;
        }
     }
+  else
+    {
+      /* non-alloc go last.  */
+      for (look = first; look; look = look->next)
+       {
+         flags = look->flags;
+         if (look->bfd_section != NULL)
+           flags = look->bfd_section->flags;
+         flags ^= sec->flags;
+         if (!(flags & SEC_DEBUGGING))
+           found = look;
+       }
+      return found;
+    }
 
   if (found || !match_type)
     return found;
@@ -1502,7 +1500,7 @@ output_prev_sec_find (lang_output_section_statement_type *os)
 
   for (lookup = os->prev; lookup != NULL; lookup = lookup->prev)
     {
-      if (lookup->constraint == -1)
+      if (lookup->constraint < 0)
        continue;
 
       if (lookup->bfd_section != NULL && lookup->bfd_section->owner != NULL)
@@ -1582,6 +1580,7 @@ insert_os_after (lang_output_section_statement_type *after)
 lang_output_section_statement_type *
 lang_insert_orphan (asection *s,
                    const char *secname,
+                   int constraint,
                    lang_output_section_statement_type *after,
                    struct orphan_save *place,
                    etree_type *address,
@@ -1637,7 +1636,7 @@ lang_insert_orphan (asection *s,
   os_tail = ((lang_output_section_statement_type **)
             lang_output_section_statement.tail);
   os = lang_enter_output_section_statement (secname, address, 0, NULL, NULL,
-                                           NULL, 0);
+                                           NULL, constraint);
 
   if (add_child == NULL)
     add_child = &os->children;
@@ -1940,10 +1939,11 @@ init_os (lang_output_section_statement_type *s, asection *isec,
   if (strcmp (s->name, DISCARD_SECTION_NAME) == 0)
     einfo (_("%P%F: Illegal use of `%s' section\n"), DISCARD_SECTION_NAME);
 
-  s->bfd_section = bfd_get_section_by_name (link_info.output_bfd, s->name);
+  if (s->constraint != SPECIAL)
+    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_with_flags (link_info.output_bfd,
-                                                 s->name, flags);
+    s->bfd_section = bfd_make_section_anyway_with_flags (link_info.output_bfd,
+                                                        s->name, flags);
   if (s->bfd_section == NULL)
     {
       einfo (_("%P%F: output format %s cannot represent section called %s\n"),
@@ -3378,7 +3378,7 @@ map_input_to_output_sections
            {
              lang_output_section_statement_type *aos
                = (lang_output_section_statement_lookup
-                  (s->address_statement.section_name));
+                  (s->address_statement.section_name, 0, TRUE));
 
              if (aos->bfd_section == NULL)
                init_os (aos, NULL, 0);
@@ -3403,6 +3403,7 @@ process_insert_statements (void)
   lang_statement_union_type **s;
   lang_output_section_statement_type *first_os = NULL;
   lang_output_section_statement_type *last_os = NULL;
+  lang_output_section_statement_type *os;
 
   /* "start of list" is actually the statement immediately after
      the special abs_section output statement, so that it isn't
@@ -3415,6 +3416,12 @@ process_insert_statements (void)
          /* Keep pointers to the first and last output section
             statement in the sequence we may be about to move.  */
          last_os = &(*s)->output_section_statement;
+
+         /* Set constraint negative so that lang_output_section_find
+            won't match this output section statement.  At this
+            stage in linking constraint has values in the range
+            [-1, ONLY_IN_RW].  */
+         last_os->constraint = -2 - last_os->constraint;
          if (first_os == NULL)
            first_os = last_os;
        }
@@ -3422,7 +3429,6 @@ process_insert_statements (void)
        {
          lang_insert_statement_type *i = &(*s)->insert_statement;
          lang_output_section_statement_type *where;
-         lang_output_section_statement_type *os;
          lang_statement_union_type **ptr;
          lang_statement_union_type *first;
 
@@ -3431,21 +3437,12 @@ process_insert_statements (void)
            {
              do
                where = where->prev;
-             while (where != NULL && where->constraint == -1);
+             while (where != NULL && where->constraint < 0);
            }
          if (where == NULL)
            {
-             einfo (_("%X%P: %s not found for insert\n"), i->where);
-             continue;
-           }
-         /* You can't insert into the list you are moving.  */
-         for (os = first_os; os != NULL; os = os->next)
-           if (os == where || os == last_os)
-             break;
-         if (os == where)
-           {
-             einfo (_("%X%P: %s not found for insert\n"), i->where);
-             continue;
+             einfo (_("%F%P: %s not found for insert\n"), i->where);
+             return;
            }
 
          /* Deal with reordering the output section statement list.  */
@@ -3482,6 +3479,7 @@ process_insert_statements (void)
              last_sec = NULL;
              for (os = first_os; os != NULL; os = os->next)
                {
+                 os->constraint = -2 - os->constraint;
                  if (os->bfd_section != NULL
                      && os->bfd_section->owner != NULL)
                    {
@@ -3542,6 +3540,14 @@ process_insert_statements (void)
          s = &lang_output_section_statement.head;
        }
     }
+
+  /* Undo constraint twiddling.  */
+  for (os = first_os; os != NULL; os = os->next)
+    {
+      os->constraint = -2 - os->constraint;
+      if (os == last_os)
+       break;
+    }
 }
 
 /* An output section might have been removed after its statement was
@@ -3569,7 +3575,7 @@ strip_excluded_output_sections (void)
       asection *output_section;
       bfd_boolean exclude;
 
-      if (os->constraint == -1)
+      if (os->constraint < 0)
        continue;
 
       output_section = os->bfd_section;
@@ -4620,7 +4626,12 @@ lang_size_sections_1
                             os->name, (unsigned long) (newdot - savedot));
                  }
 
-               bfd_set_section_vma (0, os->bfd_section, newdot);
+               /* PR 6945: Do not update the vma's of output sections
+                  when performing a relocatable link on COFF objects.  */
+               if (! link_info.relocatable
+                   || (bfd_get_flavour (link_info.output_bfd)
+                       != bfd_target_coff_flavour))
+                 bfd_set_section_vma (0, os->bfd_section, newdot);
 
                os->bfd_section->output_offset = 0;
              }
@@ -5665,23 +5676,29 @@ lang_place_orphans (void)
                      || command_line.force_common_definition)
                    {
                      if (default_common_section == NULL)
-                       {
-                         default_common_section =
-                           lang_output_section_statement_lookup (".bss");
-
-                       }
+                       default_common_section
+                         = lang_output_section_statement_lookup (".bss", 0,
+                                                                 TRUE);
                      lang_add_section (&default_common_section->children, s,
                                        default_common_section);
                    }
                }
-             else if (ldemul_place_orphan (s))
-               ;
              else
                {
-                 lang_output_section_statement_type *os;
+                 const char *name = s->name;
+                 int constraint = 0;
 
-                 os = lang_output_section_statement_lookup (s->name);
-                 lang_add_section (&os->children, s, os);
+                 if (config.unique_orphan_sections || unique_section_p (s))
+                   constraint = SPECIAL;
+
+                 if (!ldemul_place_orphan (s, name, constraint))
+                   {
+                     lang_output_section_statement_type *os;
+                     os = lang_output_section_statement_lookup (name,
+                                                                constraint,
+                                                                TRUE);
+                     lang_add_section (&os->children, s, os);
+                   }
                }
            }
        }
@@ -5827,12 +5844,10 @@ lang_enter_output_section_statement (const char *output_section_statement_name,
 {
   lang_output_section_statement_type *os;
 
-  os = lang_output_section_statement_lookup_1 (output_section_statement_name,
-                                              constraint);
+  os = lang_output_section_statement_lookup (output_section_statement_name,
+                                            constraint, TRUE);
   current_section = os;
 
-  /* Make next things chain into subchain of this.  */
-
   if (os->addr_tree == NULL)
     {
       os->addr_tree = address_exp;
@@ -5843,6 +5858,8 @@ lang_enter_output_section_statement (const char *output_section_statement_name,
   else
     os->flags = SEC_NEVER_LOAD;
   os->block_value = 1;
+
+  /* Make next things chain into subchain of this.  */
   stat_ptr = &os->children;
 
   os->subsection_alignment =
@@ -6639,7 +6656,7 @@ lang_record_phdrs (void)
        {
          lang_output_section_phdr_list *pl;
 
-         if (os->constraint == -1)
+         if (os->constraint < 0)
            continue;
 
          pl = os->phdrs;
@@ -6652,6 +6669,10 @@ lang_record_phdrs (void)
                  || (os->bfd_section->flags & SEC_ALLOC) == 0)
                continue;
 
+             /* Don't add orphans to PT_INTERP header.  */
+             if (l->type == 3)
+               continue;
+
              if (last == NULL)
                {
                  lang_output_section_statement_type * tmp_os;
@@ -6720,7 +6741,7 @@ lang_record_phdrs (void)
     {
       lang_output_section_phdr_list *pl;
 
-      if (os->constraint == -1
+      if (os->constraint < 0
          || os->bfd_section == NULL)
        continue;
 
@@ -6968,7 +6989,7 @@ lang_vers_match (struct bfd_elf_version_expr_head *head,
        java_sym = sym;
     }
 
-  if (head->htab && (prev == NULL || prev->symbol))
+  if (head->htab && (prev == NULL || prev->literal))
     {
       struct bfd_elf_version_expr e;
 
@@ -6977,9 +6998,9 @@ lang_vers_match (struct bfd_elf_version_expr_head *head,
        case 0:
          if (head->mask & BFD_ELF_VERSION_C_TYPE)
            {
-             e.symbol = sym;
+             e.pattern = sym;
              expr = htab_find (head->htab, &e);
-             while (expr && strcmp (expr->symbol, sym) == 0)
+             while (expr && strcmp (expr->pattern, sym) == 0)
                if (expr->mask == BFD_ELF_VERSION_C_TYPE)
                  goto out_ret;
                else
@@ -6989,9 +7010,9 @@ lang_vers_match (struct bfd_elf_version_expr_head *head,
        case BFD_ELF_VERSION_C_TYPE:
          if (head->mask & BFD_ELF_VERSION_CXX_TYPE)
            {
-             e.symbol = cxx_sym;
+             e.pattern = cxx_sym;
              expr = htab_find (head->htab, &e);
-             while (expr && strcmp (expr->symbol, cxx_sym) == 0)
+             while (expr && strcmp (expr->pattern, cxx_sym) == 0)
                if (expr->mask == BFD_ELF_VERSION_CXX_TYPE)
                  goto out_ret;
                else
@@ -7001,9 +7022,9 @@ lang_vers_match (struct bfd_elf_version_expr_head *head,
        case BFD_ELF_VERSION_CXX_TYPE:
          if (head->mask & BFD_ELF_VERSION_JAVA_TYPE)
            {
-             e.symbol = java_sym;
+             e.pattern = java_sym;
              expr = htab_find (head->htab, &e);
-             while (expr && strcmp (expr->symbol, java_sym) == 0)
+             while (expr && strcmp (expr->pattern, java_sym) == 0)
                if (expr->mask == BFD_ELF_VERSION_JAVA_TYPE)
                  goto out_ret;
                else
@@ -7016,7 +7037,7 @@ lang_vers_match (struct bfd_elf_version_expr_head *head,
     }
 
   /* Finally, try the wildcards.  */
-  if (prev == NULL || prev->symbol)
+  if (prev == NULL || prev->literal)
     expr = head->remaining;
   else
     expr = prev->next;
@@ -7049,7 +7070,7 @@ lang_vers_match (struct bfd_elf_version_expr_head *head,
 }
 
 /* Return NULL if the PATTERN argument is a glob pattern, otherwise,
-   return a string pointing to the symbol name.  */
+   return a pointer to the symbol name with any backslash quotes removed.  */
 
 static const char *
 realsymbol (const char *pattern)
@@ -7062,22 +7083,24 @@ realsymbol (const char *pattern)
     {
       /* It is a glob pattern only if there is no preceding
         backslash.  */
-      if (! backslash && (*p == '?' || *p == '*' || *p == '['))
-       {
-         free (symbol);
-         return NULL;
-       }
-
       if (backslash)
        {
          /* Remove the preceding backslash.  */
          *(s - 1) = *p;
+         backslash = FALSE;
          changed = TRUE;
        }
       else
-       *s++ = *p;
+       {
+         if (*p == '?' || *p == '*' || *p == '[')
+           {
+             free (symbol);
+             return NULL;
+           }
 
-      backslash = *p == '\\';
+         *s++ = *p;
+         backslash = *p == '\\';
+       }
     }
 
   if (changed)
@@ -7106,10 +7129,15 @@ lang_new_vers_pattern (struct bfd_elf_version_expr *orig,
 
   ret = xmalloc (sizeof *ret);
   ret->next = orig;
-  ret->pattern = literal_p ? NULL : new;
   ret->symver = 0;
   ret->script = 0;
-  ret->symbol = literal_p ? new : realsymbol (new);
+  ret->literal = TRUE;
+  ret->pattern = literal_p ? new : realsymbol (new);
+  if (ret->pattern == NULL)
+    {
+      ret->pattern = new;
+      ret->literal = FALSE;
+    }
 
   if (lang == NULL || strcasecmp (lang, "C") == 0)
     ret->mask = BFD_ELF_VERSION_C_TYPE;
@@ -7153,7 +7181,7 @@ version_expr_head_hash (const void *p)
 {
   const struct bfd_elf_version_expr *e = p;
 
-  return htab_hash_string (e->symbol);
+  return htab_hash_string (e->pattern);
 }
 
 static int
@@ -7162,7 +7190,7 @@ version_expr_head_eq (const void *p1, const void *p2)
   const struct bfd_elf_version_expr *e1 = p1;
   const struct bfd_elf_version_expr *e2 = p2;
 
-  return strcmp (e1->symbol, e2->symbol) == 0;
+  return strcmp (e1->pattern, e2->pattern) == 0;
 }
 
 static void
@@ -7174,7 +7202,7 @@ lang_finalize_version_expr_head (struct bfd_elf_version_expr_head *head)
 
   for (e = head->list; e; e = e->next)
     {
-      if (e->symbol)
+      if (e->literal)
        count++;
       head->mask |= e->mask;
     }
@@ -7188,7 +7216,7 @@ lang_finalize_version_expr_head (struct bfd_elf_version_expr_head *head)
       for (e = head->list; e; e = next)
        {
          next = e->next;
-         if (!e->symbol)
+         if (!e->literal)
            {
              *remaining_loc = e;
              remaining_loc = &e->next;
@@ -7213,14 +7241,14 @@ lang_finalize_version_expr_head (struct bfd_elf_version_expr_head *head)
                      last = e1;
                      e1 = e1->next;
                    }
-                 while (e1 && strcmp (e1->symbol, e->symbol) == 0);
+                 while (e1 && strcmp (e1->pattern, e->pattern) == 0);
 
                  if (last == NULL)
                    {
                      /* This is a duplicate.  */
                      /* FIXME: Memory leak.  Sometimes pattern is not
                         xmalloced alone, but in larger chunk of memory.  */
-                     /* free (e->symbol); */
+                     /* free (e->pattern); */
                      free (e);
                    }
                  else
@@ -7284,18 +7312,18 @@ lang_register_vers_node (const char *name,
        {
          struct bfd_elf_version_expr *e2;
 
-         if (t->locals.htab && e1->symbol)
+         if (t->locals.htab && e1->literal)
            {
              e2 = htab_find (t->locals.htab, e1);
-             while (e2 && strcmp (e1->symbol, e2->symbol) == 0)
+             while (e2 && strcmp (e1->pattern, e2->pattern) == 0)
                {
                  if (e1->mask == e2->mask)
                    einfo (_("%X%P: duplicate expression `%s'"
-                            " in version information\n"), e1->symbol);
+                            " in version information\n"), e1->pattern);
                  e2 = e2->next;
                }
            }
-         else if (!e1->symbol)
+         else if (!e1->literal)
            for (e2 = t->locals.remaining; e2 != NULL; e2 = e2->next)
              if (strcmp (e1->pattern, e2->pattern) == 0
                  && e1->mask == e2->mask)
@@ -7310,19 +7338,19 @@ lang_register_vers_node (const char *name,
        {
          struct bfd_elf_version_expr *e2;
 
-         if (t->globals.htab && e1->symbol)
+         if (t->globals.htab && e1->literal)
            {
              e2 = htab_find (t->globals.htab, e1);
-             while (e2 && strcmp (e1->symbol, e2->symbol) == 0)
+             while (e2 && strcmp (e1->pattern, e2->pattern) == 0)
                {
                  if (e1->mask == e2->mask)
                    einfo (_("%X%P: duplicate expression `%s'"
                             " in version information\n"),
-                          e1->symbol);
+                          e1->pattern);
                  e2 = e2->next;
                }
            }
-         else if (!e1->symbol)
+         else if (!e1->literal)
            for (e2 = t->globals.remaining; e2 != NULL; e2 = e2->next)
              if (strcmp (e1->pattern, e2->pattern) == 0
                  && e1->mask == e2->mask)
This page took 0.033821 seconds and 4 git commands to generate.