bfd/
[deliverable/binutils-gdb.git] / bfd / elflink.c
index 1dad504772786d0f80e427f4cd01013a25b6343a..9630709758bbeddf79bae2c1d32e421cbd0f3fc8 100644 (file)
@@ -185,16 +185,6 @@ _bfd_elf_link_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
        return FALSE;
     }
 
-  if (! info->traditional_format)
-    {
-      s = bfd_make_section_with_flags (abfd, ".eh_frame_hdr",
-                                      flags | SEC_READONLY);
-      if (s == NULL
-         || ! bfd_set_section_alignment (abfd, s, 2))
-       return FALSE;
-      elf_hash_table (info)->eh_info.hdr_sec = s;
-    }
-
   /* Create sections to hold version informations.  These are removed
      if they are not needed.  */
   s = bfd_make_section_with_flags (abfd, ".gnu.version_d",
@@ -448,14 +438,22 @@ bfd_elf_link_record_dynamic_symbol (struct bfd_link_info *info,
 
 void
 bfd_elf_link_mark_dynamic_symbol (struct bfd_link_info *info,
-                                 struct elf_link_hash_entry *h)
+                                 struct elf_link_hash_entry *h,
+                                 Elf_Internal_Sym *sym)
 {
-  struct bfd_elf_dynamic_list *d = info->dynamic;
+  struct bfd_elf_dynamic_list *d = info->dynamic_list;
 
-  if (d == NULL || info->relocatable)
+  /* It may be called more than once on the same H.  */
+  if(h->dynamic || info->relocatable)
     return;
 
-  if ((*d->match) (&d->head, NULL, h->root.root.string))
+  if ((info->dynamic_data
+       && (h->type == STT_OBJECT
+          || (sym != NULL
+              && ELF_ST_TYPE (sym->st_info) == STT_OBJECT)))
+      || (d != NULL 
+         && h->root.type == bfd_link_hash_new
+         && (*d->match) (&d->head, NULL, h->root.root.string)))
     h->dynamic = 1;
 }
 
@@ -493,7 +491,7 @@ bfd_elf_record_link_assignment (bfd *output_bfd,
 
   if (h->root.type == bfd_link_hash_new)
     {
-      bfd_elf_link_mark_dynamic_symbol (info, h);
+      bfd_elf_link_mark_dynamic_symbol (info, h, NULL);
       h->non_elf = 0;
     }
 
@@ -871,13 +869,17 @@ _bfd_elf_merge_symbol (bfd *abfd,
         || h->root.type == bfd_link_hash_warning)
     h = (struct elf_link_hash_entry *) h->root.u.i.link;
 
+  /* We have to check it for every instance since the first few may be
+     refereences and not all compilers emit symbol type for undefined
+     symbols.  */
+  bfd_elf_link_mark_dynamic_symbol (info, h, sym);
+
   /* If we just created the symbol, mark it as being an ELF symbol.
      Other than that, there is nothing to do--there is no merge issue
      with a newly defined symbol--so we just return.  */
 
   if (h->root.type == bfd_link_hash_new)
     {
-      bfd_elf_link_mark_dynamic_symbol (info, h);
       h->non_elf = 0;
       return TRUE;
     }
@@ -3692,12 +3694,10 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
            sec = bfd_abs_section_ptr;
          else if (sec->kept_section)
            {
-             /* Symbols from discarded section are undefined, and have
-                default visibility.  */
+             /* Symbols from discarded section are undefined.  We keep
+                its visibility.  */
              sec = bfd_und_section_ptr;
              isym->st_shndx = SHN_UNDEF;
-             isym->st_other = (STV_DEFAULT
-                               | (isym->st_other & ~ ELF_ST_VISIBILITY (-1)));
            }
          else if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0)
            value -= sec->vma;
@@ -4047,11 +4047,13 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
                }
            }
 
-         /* Remember the symbol size and type.  */
-         if (isym->st_size != 0
+         /* Remember the symbol size if it isn't undefined.  */
+         if ((isym->st_size != 0 && isym->st_shndx != SHN_UNDEF)
              && (definition || h->size == 0))
            {
-             if (h->size != 0 && h->size != isym->st_size && ! size_change_ok)
+             if (h->size != 0
+                 && h->size != isym->st_size
+                 && ! size_change_ok)
                (*_bfd_error_handler)
                  (_("Warning: size of symbol `%s' changed"
                     " from %lu in %B to %lu in %B"),
@@ -4263,6 +4265,8 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
       unsigned int i;
 
       /* Restore the symbol table.  */
+      if (bed->as_needed_cleanup)
+       (*bed->as_needed_cleanup) (abfd, info);
       old_hash = (char *) old_tab + tabsize;
       old_ent = (char *) old_hash + hashsize;
       sym_hash = elf_sym_hashes (abfd);
@@ -5281,6 +5285,9 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
       && ! (*bed->elf_backend_always_size_sections) (output_bfd, info))
     return FALSE;
 
+  if (! _bfd_elf_maybe_strip_eh_frame_hdr (info))
+    return FALSE;
+
   dynobj = elf_hash_table (info)->dynobj;
 
   /* If there were no dynamic objects in the link, there is nothing to
@@ -5288,9 +5295,6 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
   if (dynobj == NULL)
     return TRUE;
 
-  if (! _bfd_elf_maybe_strip_eh_frame_hdr (info))
-    return FALSE;
-
   if (elf_hash_table (info)->dynamic_sections_created)
     {
       struct elf_info_failed eif;
@@ -7267,14 +7271,15 @@ _bfd_elf_default_action_discarded (asection *sec)
 /* Find a match between a section and a member of a section group.  */
 
 static asection *
-match_group_member (asection *sec, asection *group)
+match_group_member (asection *sec, asection *group,
+                   struct bfd_link_info *info)
 {
   asection *first = elf_next_in_group (group);
   asection *s = first;
 
   while (s != NULL)
     {
-      if (bfd_elf_match_symbols_in_sections (s, sec))
+      if (bfd_elf_match_symbols_in_sections (s, sec, info))
        return s;
 
       s = elf_next_in_group (s);
@@ -7286,21 +7291,22 @@ match_group_member (asection *sec, asection *group)
 }
 
 /* Check if the kept section of a discarded section SEC can be used
-   to replace it. Return the replacement if it is OK. Otherwise return
-   NULL. */
+   to replace it.  Return the replacement if it is OK.  Otherwise return
+   NULL.  */
 
 asection *
-_bfd_elf_check_kept_section (asection *sec)
+_bfd_elf_check_kept_section (asection *sec, struct bfd_link_info *info)
 {
   asection *kept;
 
   kept = sec->kept_section;
   if (kept != NULL)
     {
-      if (elf_sec_group (sec) != NULL)
-       kept = match_group_member (sec, kept);
+      if ((kept->flags & SEC_GROUP) != 0)
+       kept = match_group_member (sec, kept, info);
       if (kept != NULL && sec->size != kept->size)
        kept = NULL;
+      sec->kept_section = kept;
     }
   return kept;
 }
@@ -7651,7 +7657,8 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
                        {
                          asection *kept;
 
-                         kept = _bfd_elf_check_kept_section (sec);
+                         kept = _bfd_elf_check_kept_section (sec,
+                                                             finfo->info);
                          if (kept != NULL)
                            {
                              *ps = kept;
@@ -8800,6 +8807,17 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
        }
     }
 
+  /* Free symbol buffer if needed.  */
+  if (!info->reduce_memory_overheads)
+    {
+      for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
+       if (elf_tdata (sub)->symbuf)
+         {
+           free (elf_tdata (sub)->symbuf);
+           elf_tdata (sub)->symbuf = NULL;
+         }
+    }
+
   /* Output any global symbols that got converted to local in a
      version script or due to symbol visibility.  We do this in a
      separate step since ELF requires all local symbols to appear
@@ -9807,13 +9825,15 @@ bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info)
       if (bfd_get_flavour (sub) != bfd_target_elf_flavour)
        continue;
 
-      /* Keep .gcc_except_table.* if the associated .text.* is
+      /* Keep .gcc_except_table.* if the associated .text.* (or the
+        associated .gnu.linkonce.t.* if .text.* doesn't exist) is
         marked.  This isn't very nice, but the proper solution,
         splitting .eh_frame up and using comdat doesn't pan out
         easily due to needing special relocs to handle the
         difference of two symbols in separate sections.
         Don't keep code sections referenced by .eh_frame.  */
 #define TEXT_PREFIX                    ".text."
+#define TEXT_PREFIX2                   ".gnu.linkonce.t."
 #define GCC_EXCEPT_TABLE_PREFIX                ".gcc_except_table."
       for (o = sub->sections; o != NULL; o = o->next)
        if (!o->gc_mark && o->gc_mark_from_eh && (o->flags & SEC_CODE) == 0)
@@ -9823,15 +9843,30 @@ bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info)
                char *fn_name;
                const char *sec_name;
                asection *fn_text;
-               unsigned o_name_prefix_len  = strlen (GCC_EXCEPT_TABLE_PREFIX);
-               unsigned fn_name_prefix_len = strlen (TEXT_PREFIX);
+               unsigned o_name_prefix_len , fn_name_prefix_len, tmp;
 
+               o_name_prefix_len = strlen (GCC_EXCEPT_TABLE_PREFIX);
                sec_name = o->name + o_name_prefix_len;
-               fn_name = bfd_malloc (strlen (sec_name) + fn_name_prefix_len + 1);
+               fn_name_prefix_len = strlen (TEXT_PREFIX);
+               tmp = strlen (TEXT_PREFIX2);
+               if (tmp > fn_name_prefix_len)
+                 fn_name_prefix_len = tmp;
+               fn_name
+                 = bfd_malloc (fn_name_prefix_len + strlen (sec_name) + 1);
                if (fn_name == NULL)
                  return FALSE;
+
+               /* Try the first prefix.  */
                sprintf (fn_name, "%s%s", TEXT_PREFIX, sec_name);
                fn_text = bfd_get_section_by_name (sub, fn_name);
+
+               /* Try the second prefix.  */
+               if (fn_text == NULL)
+                 {
+                   sprintf (fn_name, "%s%s", TEXT_PREFIX2, sec_name);
+                   fn_text = bfd_get_section_by_name (sub, fn_name);
+                 }
+
                free (fn_name);
                if (fn_text == NULL || !fn_text->gc_mark)
                  continue;
@@ -10296,39 +10331,28 @@ bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info)
 }
 
 void
-_bfd_elf_section_already_linked (bfd *abfd, struct bfd_section * sec)
+_bfd_elf_section_already_linked (bfd *abfd, struct bfd_section *sec,
+                                struct bfd_link_info *info)
 {
   flagword flags;
   const char *name, *p;
   struct bfd_section_already_linked *l;
   struct bfd_section_already_linked_hash_entry *already_linked_list;
-  asection *group;
 
-  /* A single member comdat group section may be discarded by a
-     linkonce section. See below.  */
   if (sec->output_section == bfd_abs_section_ptr)
     return;
 
   flags = sec->flags;
 
-  /* Check if it belongs to a section group.  */
-  group = elf_sec_group (sec);
-
-  /* Return if it isn't a linkonce section nor a member of a group.  A
-     comdat group section also has SEC_LINK_ONCE set.  */
-  if ((flags & SEC_LINK_ONCE) == 0 && group == NULL)
+  /* Return if it isn't a linkonce section.  A comdat group section
+     also has SEC_LINK_ONCE set.  */
+  if ((flags & SEC_LINK_ONCE) == 0)
     return;
 
-  if (group)
-    {
-      /* If this is the member of a single member comdat group, check if
-        the group should be discarded.  */
-      if (elf_next_in_group (sec) == sec
-         && (group->flags & SEC_LINK_ONCE) != 0)
-       sec = group;
-      else
-       return;
-    }
+  /* Don't put group member sections on our list of already linked
+     sections.  They are handled as a group via their group section.  */
+  if (elf_sec_group (sec) != NULL)
+    return;
 
   /* FIXME: When doing a relocatable link, we may have trouble
      copying relocations in other sections that refer to local symbols
@@ -10359,11 +10383,8 @@ _bfd_elf_section_already_linked (bfd *abfd, struct bfd_section * sec)
 
   for (l = already_linked_list->entry; l != NULL; l = l->next)
     {
-      /* We may have 3 different sections on the list: group section,
-        comdat section and linkonce section. SEC may be a linkonce or
-        group section. We match a group section with a group section,
-        a linkonce section with a linkonce section, and ignore comdat
-        section.  */
+      /* We may have 2 different types of sections on the list: group
+        sections and linkonce sections.  Match like sections.  */
       if ((flags & SEC_GROUP) == (l->sec->flags & SEC_GROUP)
          && strcmp (name, l->sec->name) == 0
          && bfd_coff_get_comdat_section (l->sec->owner, l->sec) == NULL)
@@ -10451,31 +10472,28 @@ _bfd_elf_section_already_linked (bfd *abfd, struct bfd_section * sec)
        }
     }
 
-  if (group)
+  /* A single member comdat group section may be discarded by a
+     linkonce section and vice versa.  */
+
+  if ((flags & SEC_GROUP) != 0)
     {
-      /* If this is the member of a single member comdat group and the
-        group hasn't be discarded, we check if it matches a linkonce
-        section. We only record the discarded comdat group. Otherwise
-        the undiscarded group will be discarded incorrectly later since
-        itself has been recorded.  */
-      for (l = already_linked_list->entry; l != NULL; l = l->next)
-       if ((l->sec->flags & SEC_GROUP) == 0
-           && bfd_coff_get_comdat_section (l->sec->owner, l->sec) == NULL
-           && bfd_elf_match_symbols_in_sections (l->sec,
-                                                 elf_next_in_group (sec)))
-         {
-           elf_next_in_group (sec)->output_section = bfd_abs_section_ptr;
-           elf_next_in_group (sec)->kept_section = l->sec;
-           group->output_section = bfd_abs_section_ptr;
-           break;
-         }
-      if (l == NULL)
-       return;
+      asection *first = elf_next_in_group (sec);
+
+      if (first != NULL && elf_next_in_group (first) == first)
+       /* Check this single member group against linkonce sections.  */
+       for (l = already_linked_list->entry; l != NULL; l = l->next)
+         if ((l->sec->flags & SEC_GROUP) == 0
+             && bfd_coff_get_comdat_section (l->sec->owner, l->sec) == NULL
+             && bfd_elf_match_symbols_in_sections (l->sec, first, info))
+           {
+             first->output_section = bfd_abs_section_ptr;
+             first->kept_section = l->sec;
+             sec->output_section = bfd_abs_section_ptr;
+             break;
+           }
     }
   else
-    /* There is no direct match. But for linkonce section, we should
-       check if there is a match with comdat group member. We always
-       record the linkonce section, discarded or not.  */
+    /* Check this linkonce section against single member groups.  */
     for (l = already_linked_list->entry; l != NULL; l = l->next)
       if (l->sec->flags & SEC_GROUP)
        {
@@ -10483,10 +10501,10 @@ _bfd_elf_section_already_linked (bfd *abfd, struct bfd_section * sec)
 
          if (first != NULL
              && elf_next_in_group (first) == first
-             && bfd_elf_match_symbols_in_sections (first, sec))
+             && bfd_elf_match_symbols_in_sections (first, sec, info))
            {
              sec->output_section = bfd_abs_section_ptr;
-             sec->kept_section = l->sec;
+             sec->kept_section = first;
              break;
            }
        }
This page took 0.0315 seconds and 4 git commands to generate.