bfd/
[deliverable/binutils-gdb.git] / bfd / elflink.c
index 3614575d23dbecbdaaa7f7ed46843849c1c7d415..a9d95bd1b0a7c0bef7956d632f90d06a98c63fae 100644 (file)
@@ -1216,15 +1216,15 @@ _bfd_elf_merge_symbol (bfd *abfd,
            h = *sym_hash;
        }
 
-      if ((h->root.u.undef.next || info->hash->undefs_tail == &h->root)
-         && bfd_is_und_section (sec))
-       {
-         /* If the new symbol is undefined and the old symbol was
-            also undefined before, we need to make sure
-            _bfd_generic_link_add_one_symbol doesn't mess
-            up the linker hash table undefs list.  Since the old
-            definition came from a dynamic object, it is still on the
-            undefs list.  */
+      /* If the old symbol was undefined before, then it will still be
+        on the undefs list.  If the new symbol is undefined or
+        common, we can't make it bfd_link_hash_new here, because new
+        undefined or common symbols will be added to the undefs list
+        by _bfd_generic_link_add_one_symbol.  Symbols may not be
+        added twice to the undefs list.  Also, if the new symbol is
+        undefweak then we don't want to lose the strong undef.  */
+      if (h->root.u.undef.next || info->hash->undefs_tail == &h->root)
+       {
          h->root.type = bfd_link_hash_undefined;
          h->root.u.undef.abfd = abfd;
        }
@@ -1234,11 +1234,18 @@ _bfd_elf_merge_symbol (bfd *abfd,
          h->root.u.undef.abfd = NULL;
        }
 
-      if (h->def_dynamic)
+      if (ELF_ST_VISIBILITY (sym->st_other) != STV_PROTECTED)
        {
-         h->def_dynamic = 0;
-         h->ref_dynamic = 1;
+         /* If the new symbol is hidden or internal, completely undo
+            any dynamic link state.  */
+         (*bed->elf_backend_hide_symbol) (info, h, TRUE);
+         h->forced_local = 0;
+         h->ref_dynamic = 0;
        }
+      else
+       h->ref_dynamic = 1;
+      h->def_dynamic = 0;
+      h->dynamic_def = 0;
       /* FIXME: Should we check type and size for protected symbol?  */
       h->size = 0;
       h->type = 0;
@@ -5584,17 +5591,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
-     do here.  */
-  if (dynobj == NULL)
-    return TRUE;
-
-  if (elf_hash_table (info)->dynamic_sections_created)
+  if (dynobj != NULL && elf_hash_table (info)->dynamic_sections_created)
     {
       struct elf_info_failed eif;
       struct elf_link_hash_entry *h;
@@ -5897,11 +5896,15 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
 
   /* The backend must work out the sizes of all the other dynamic
      sections.  */
-  if (bed->elf_backend_size_dynamic_sections
+  if (dynobj != NULL
+      && bed->elf_backend_size_dynamic_sections != NULL
       && ! (*bed->elf_backend_size_dynamic_sections) (output_bfd, info))
     return FALSE;
 
-  if (elf_hash_table (info)->dynamic_sections_created)
+  if (! _bfd_elf_maybe_strip_eh_frame_hdr (info))
+    return FALSE;
+
+  if (dynobj != NULL && elf_hash_table (info)->dynamic_sections_created)
     {
       unsigned long section_sym_count;
       struct bfd_elf_version_tree *verdefs;
@@ -7400,6 +7403,8 @@ struct elf_final_link_info
   size_t symbuf_size;
   /* And same for symshndxbuf.  */
   size_t shndxbuf_size;
+  /* Number of STT_FILE syms seen.  */
+  size_t filesym_count;
 };
 
 /* This struct is used to pass information to elf_link_output_extsym.  */
@@ -7408,6 +7413,8 @@ struct elf_outext_info
 {
   bfd_boolean failed;
   bfd_boolean localsyms;
+  bfd_boolean need_second_pass;
+  bfd_boolean second_pass;
   struct elf_final_link_info *flinfo;
 };
 
@@ -8602,6 +8609,11 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
     {
       if (!h->forced_local)
        return TRUE;
+      if (eoinfo->second_pass
+         && !((h->root.type == bfd_link_hash_defined
+               || h->root.type == bfd_link_hash_defweak)
+              && h->root.u.def.section->output_section != NULL))
+       return TRUE;
     }
   else
     {
@@ -8756,6 +8768,19 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
        input_sec = h->root.u.def.section;
        if (input_sec->output_section != NULL)
          {
+           if (eoinfo->localsyms && flinfo->filesym_count == 1)
+             {
+               bfd_boolean second_pass_sym
+                 = (input_sec->owner == flinfo->output_bfd
+                    || input_sec->owner == NULL
+                    || (input_sec->flags & SEC_LINKER_CREATED) != 0
+                    || (input_sec->owner->flags & BFD_LINKER_CREATED) != 0);
+
+               eoinfo->need_second_pass |= second_pass_sym;
+               if (eoinfo->second_pass != second_pass_sym)
+                 return TRUE;
+             }
+
            sym.st_shndx =
              _bfd_elf_section_from_bfd_section (flinfo->output_bfd,
                                                 input_sec->output_section);
@@ -9108,6 +9133,7 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
   bfd_size_type address_size;
   bfd_vma r_type_mask;
   int r_sym_shift;
+  bfd_boolean have_file_sym = FALSE;
 
   output_bfd = flinfo->output_bfd;
   bed = get_elf_backend_data (output_bfd);
@@ -9243,6 +9269,29 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
              && bfd_is_local_label_name (input_bfd, name)))
        continue;
 
+      if (ELF_ST_TYPE (isym->st_info) == STT_FILE)
+       {
+         have_file_sym = TRUE;
+         flinfo->filesym_count += 1;
+       }
+      if (!have_file_sym)
+       {
+         /* In the absence of debug info, bfd_find_nearest_line uses
+            FILE symbols to determine the source file for local
+            function symbols.  Provide a FILE symbol here if input
+            files lack such, so that their symbols won't be
+            associated with a previous input file.  It's not the
+            source file, but the best we can do.  */
+         have_file_sym = TRUE;
+         flinfo->filesym_count += 1;
+         memset (&osym, 0, sizeof (osym));
+         osym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FILE);
+         osym.st_shndx = SHN_ABS;
+         if (!elf_link_output_sym (flinfo, input_bfd->filename, &osym,
+                                   bfd_abs_section_ptr, NULL))
+           return FALSE;
+       }
+
       osym = *isym;
 
       /* Adjust the section index for the output file.  */
@@ -10315,6 +10364,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   flinfo.symshndxbuf = NULL;
   flinfo.symbuf_count = 0;
   flinfo.shndxbuf_size = 0;
+  flinfo.filesym_count = 0;
 
   /* The object attributes have been merged.  Remove the input
      sections from the link, and set the contents of the output
@@ -10789,6 +10839,17 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
          }
     }
 
+  /* Output a FILE symbol so that following locals are not associated
+     with the wrong input file.  */
+  memset (&elfsym, 0, sizeof (elfsym));
+  elfsym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FILE);
+  elfsym.st_shndx = SHN_ABS;
+
+  if (flinfo.filesym_count > 1
+      && !elf_link_output_sym (&flinfo, NULL, &elfsym,
+                              bfd_und_section_ptr, NULL))
+    return FALSE;
+
   /* 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
@@ -10798,10 +10859,25 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
   eoinfo.failed = FALSE;
   eoinfo.flinfo = &flinfo;
   eoinfo.localsyms = TRUE;
+  eoinfo.need_second_pass = FALSE;
+  eoinfo.second_pass = FALSE;
   bfd_hash_traverse (&info->hash->table, elf_link_output_extsym, &eoinfo);
   if (eoinfo.failed)
     return FALSE;
 
+  if (flinfo.filesym_count == 1
+      && !elf_link_output_sym (&flinfo, NULL, &elfsym,
+                              bfd_und_section_ptr, NULL))
+    return FALSE;
+
+  if (eoinfo.need_second_pass)
+    {
+      eoinfo.second_pass = TRUE;
+      bfd_hash_traverse (&info->hash->table, elf_link_output_extsym, &eoinfo);
+      if (eoinfo.failed)
+       return FALSE;
+    }
+
   /* If backend needs to output some local symbols not present in the hash
      table, do it now.  */
   if (bed->elf_backend_output_arch_local_syms)
@@ -12002,12 +12078,14 @@ bfd_elf_gc_sections (bfd *abfd, struct bfd_link_info *info)
       struct elf_reloc_cookie cookie;
 
       sec = bfd_get_section_by_name (sub, ".eh_frame");
-      if (sec && init_reloc_cookie_for_section (&cookie, info, sec))
+      while (sec && init_reloc_cookie_for_section (&cookie, info, sec))
        {
          _bfd_elf_parse_eh_frame (sub, info, sec, &cookie);
-         if (elf_section_data (sec)->sec_info)
+         if (elf_section_data (sec)->sec_info
+             && (sec->flags & SEC_LINKER_CREATED) == 0)
            elf_eh_frame_section (sub) = sec;
          fini_reloc_cookie_for_section (&cookie, sec);
+         sec = bfd_get_next_section_by_name (sec);
        }
     }
   _bfd_elf_end_eh_frame_parsing (info);
@@ -12482,17 +12560,14 @@ bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info)
 
       bed = get_elf_backend_data (abfd);
 
-      if ((abfd->flags & DYNAMIC) != 0)
-       continue;
-
       eh = NULL;
       if (!info->relocatable)
        {
          eh = bfd_get_section_by_name (abfd, ".eh_frame");
-         if (eh != NULL
-             && (eh->size == 0
-                 || bfd_is_abs_section (eh->output_section)))
-           eh = NULL;
+         while (eh != NULL
+                && (eh->size == 0
+                    || bfd_is_abs_section (eh->output_section)))
+           eh = bfd_get_next_section_by_name (eh);
        }
 
       stab = bfd_get_section_by_name (abfd, ".stab");
@@ -12522,8 +12597,8 @@ bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info)
          fini_reloc_cookie_rels (&cookie, stab);
        }
 
-      if (eh != NULL
-         && init_reloc_cookie_rels (&cookie, info, abfd, eh))
+      while (eh != NULL
+            && init_reloc_cookie_rels (&cookie, info, abfd, eh))
        {
          _bfd_elf_parse_eh_frame (abfd, info, eh, &cookie);
          if (_bfd_elf_discard_section_eh_frame (abfd, info, eh,
@@ -12531,6 +12606,7 @@ bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info)
                                                 &cookie))
            ret = TRUE;
          fini_reloc_cookie_rels (&cookie, eh);
+         eh = bfd_get_next_section_by_name (eh);
        }
 
       if (bed->elf_backend_discard_info != NULL
This page took 0.029952 seconds and 4 git commands to generate.