* gdb.threads/linux-dp.exp: Unset 'seen' before 'array set'.
[deliverable/binutils-gdb.git] / binutils / objcopy.c
index ac176df589641982c2c3fdcdb2e87599a8e2b01f..a48ac4338d5368589da344a98140b658a58f3e77 100644 (file)
@@ -1,6 +1,6 @@
 /* objcopy.c -- copy object file from input to output, optionally massaging it.
    Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
-   2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+   2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
    Free Software Foundation, Inc.
 
    This file is part of GNU Binutils.
@@ -30,7 +30,6 @@
 #include "filenames.h"
 #include "fnmatch.h"
 #include "elf-bfd.h"
-#include <sys/stat.h>
 #include "libbfd.h"
 #include "coff/internal.h"
 #include "libcoff.h"
@@ -460,6 +459,7 @@ extern bfd_boolean S3Forced;
 /* Forward declarations.  */
 static void setup_section (bfd *, asection *, void *);
 static void setup_bfd_headers (bfd *, bfd *);
+static void copy_relocations_in_section (bfd *, asection *, void *);
 static void copy_section (bfd *, asection *, void *);
 static void get_sections (bfd *, asection *, void *);
 static int compare_section_lma (const void *, const void *);
@@ -925,10 +925,10 @@ group_signature (asection *group)
   return NULL;
 }
 
-/* See if a section is being removed.  */
+/* See if a non-group section is being removed.  */
 
 static bfd_boolean
-is_strip_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
+is_strip_section_1 (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
 {
   if (sections_removed || sections_copied)
     {
@@ -955,10 +955,22 @@ is_strip_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
        return FALSE;
     }
 
+  return FALSE;
+}
+
+/* See if a section is being removed.  */
+
+static bfd_boolean
+is_strip_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
+{
+  if (is_strip_section_1 (abfd, sec))
+    return TRUE;
+
   if ((bfd_get_section_flags (abfd, sec) & SEC_GROUP) != 0)
     {
       asymbol *gsym;
       const char *gname;
+      asection *elt, *first;
 
       /* PR binutils/3181
         If we are going to strip the group signature symbol, then
@@ -972,6 +984,19 @@ is_strip_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
           && !is_specified_symbol (gname, keep_specific_htab))
          || is_specified_symbol (gname, strip_specific_htab))
        return TRUE;
+
+      /* Remove the group section if all members are removed.  */
+      first = elt = elf_next_in_group (sec);
+      while (elt != NULL)
+       {
+         if (!is_strip_section_1 (abfd, elt))
+           return FALSE;
+         elt = elf_next_in_group (elt);
+         if (elt == first)
+           break;
+       }
+
+      return TRUE;
     }
 
   return FALSE;
@@ -1399,7 +1424,9 @@ copy_unknown_object (bfd *ibfd, bfd *obfd)
       ncopied += tocopy;
     }
 
-  chmod (bfd_get_filename (obfd), buf.st_mode);
+  /* We should at least to be able to read it back when copying an
+     unknown object in an archive.  */
+  chmod (bfd_get_filename (obfd), buf.st_mode | S_IRUSR);
   free (cbuf);
   return TRUE;
 }
@@ -1859,6 +1886,9 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
 
   bfd_set_symtab (obfd, osympp, symcount);
 
+  /* This has to happen before section positions are set.  */
+  bfd_map_over_sections (ibfd, copy_relocations_in_section, obfd);
+
   /* This has to happen after the symbol table has been set.  */
   bfd_map_over_sections (ibfd, copy_section, obfd);
 
@@ -2022,6 +2052,7 @@ copy_archive (bfd *ibfd, bfd *obfd, const char *output_target,
       struct stat buf;
       int stat_status = 0;
       bfd_boolean del = TRUE;
+      bfd_boolean ok_object;
 
       /* Create an output file for this member.  */
       output_name = concat (dir, "/",
@@ -2059,44 +2090,42 @@ copy_archive (bfd *ibfd, bfd *obfd, const char *output_target,
       l->obfd = NULL;
       list = l;
 
-      if (bfd_check_format (this_element, bfd_object))
+      ok_object = bfd_check_format (this_element, bfd_object);
+      if (!ok_object)
+       bfd_nonfatal_message (NULL, this_element, NULL,
+                             _("Unable to recognise the format of file"));
+
+      /* PR binutils/3110: Cope with archives
+        containing multiple target types.  */
+      if (force_output_target || !ok_object)
+       output_bfd = bfd_openw (output_name, output_target);
+      else
+       output_bfd = bfd_openw (output_name, bfd_get_target (this_element));
+
+      if (output_bfd == NULL)
        {
-         /* PR binutils/3110: Cope with archives
-            containing multiple target types.  */
-         if (force_output_target)
-           output_bfd = bfd_openw (output_name, output_target);
-         else
-           output_bfd = bfd_openw (output_name, bfd_get_target (this_element));
+         bfd_nonfatal_message (output_name, NULL, NULL, NULL);
+         status = 1;
+         return;
+       }
+
+      if (ok_object)
+       {
+         del = !copy_object (this_element, output_bfd, input_arch);
 
-         if (output_bfd == NULL)
+         if (del && bfd_get_arch (this_element) == bfd_arch_unknown)
+           /* Try again as an unknown object file.  */
+           ok_object = FALSE;
+         else if (!bfd_close (output_bfd))
            {
              bfd_nonfatal_message (output_name, NULL, NULL, NULL);
+             /* Error in new object file. Don't change archive.  */
              status = 1;
-             return;
-           }
-
-         del = ! copy_object (this_element, output_bfd, input_arch);
-
-         if (! del
-             || bfd_get_arch (this_element) != bfd_arch_unknown)
-           {
-             if (!bfd_close (output_bfd))
-               {
-                 bfd_nonfatal_message (output_name, NULL, NULL, NULL);
-                 /* Error in new object file. Don't change archive.  */
-                 status = 1;
-               }
            }
-         else
-           goto copy_unknown_element;
        }
-      else
-       {
-         bfd_nonfatal_message (NULL, this_element, NULL,
-                               _("Unable to recognise the format of file"));
 
-         output_bfd = bfd_openw (output_name, output_target);
-copy_unknown_element:
+      if (!ok_object)
+       {
          del = !copy_unknown_object (this_element, output_bfd);
          if (!bfd_close_all_done (output_bfd))
            {
@@ -2563,44 +2592,56 @@ loser:
   bfd_nonfatal_message (NULL, obfd, osection, err);
 }
 
-/* Copy the data of input section ISECTION of IBFD
-   to an output section with the same name in OBFD.
-   If stripping then don't copy any relocation info.  */
+/* Return TRUE if input section ISECTION should be skipped.  */
 
-static void
-copy_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
+static bfd_boolean
+skip_section (bfd *ibfd, sec_ptr isection)
 {
-  bfd *obfd = (bfd *) obfdarg;
-  struct section_list *p;
-  arelent **relpp;
-  long relcount;
   sec_ptr osection;
   bfd_size_type size;
-  long relsize;
   flagword flags;
 
   /* If we have already failed earlier on,
      do not keep on generating complaints now.  */
   if (status != 0)
-    return;
+    return TRUE;
+
+  if (extract_symbol)
+    return TRUE;
 
   if (is_strip_section (ibfd, isection))
-    return;
+    return TRUE;
 
   flags = bfd_get_section_flags (ibfd, isection);
   if ((flags & SEC_GROUP) != 0)
-    return;
+    return TRUE;
 
   osection = isection->output_section;
   size = bfd_get_section_size (isection);
 
   if (size == 0 || osection == 0)
-    return;
+    return TRUE;
 
-  if (extract_symbol)
+  return FALSE;
+}
+
+/* Copy relocations in input section ISECTION of IBFD to an output
+   section with the same name in OBFDARG.  If stripping then don't
+   copy any relocation info.  */
+
+static void
+copy_relocations_in_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
+{
+  bfd *obfd = (bfd *) obfdarg;
+  long relsize;
+  arelent **relpp;
+  long relcount;
+  sec_ptr osection;
+
+  if (skip_section (ibfd, isection))
     return;
 
-  p = find_section_list (bfd_get_section_name (ibfd, isection), FALSE);
+  osection = isection->output_section;
 
   /* Core files do not need to be relocated.  */
   if (bfd_get_format (obfd) == bfd_core)
@@ -2657,8 +2698,31 @@ copy_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
 
       bfd_set_reloc (obfd, osection, relcount == 0 ? NULL : relpp, relcount);
       if (relcount == 0)
-       free (relpp);
+       {
+         osection->flags &= ~SEC_RELOC;
+         free (relpp);
+       }
     }
+}
+
+/* Copy the data of input section ISECTION of IBFD
+   to an output section with the same name in OBFD.  */
+
+static void
+copy_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
+{
+  bfd *obfd = (bfd *) obfdarg;
+  struct section_list *p;
+  sec_ptr osection;
+  bfd_size_type size;
+
+  if (skip_section (ibfd, isection))
+    return;
+
+  osection = isection->output_section;
+  size = bfd_get_section_size (isection);
+
+  p = find_section_list (bfd_get_section_name (ibfd, isection), FALSE);
 
   if (bfd_get_section_flags (ibfd, isection) & SEC_HAS_CONTENTS
       && bfd_get_section_flags (obfd, osection) & SEC_HAS_CONTENTS)
@@ -3035,7 +3099,8 @@ strip_main (int argc, char *argv[])
           It has already been checked in get_file_size().  */
        stat (argv[i], &statbuf);
 
-      if (output_file == NULL || strcmp (argv[i], output_file) == 0)
+      if (output_file == NULL
+         || filename_cmp (argv[i], output_file) == 0)
        tmpname = make_tempname (argv[i]);
       else
        tmpname = output_file;
@@ -3156,6 +3221,8 @@ set_pe_subsystem (const char *s)
        pe_section_alignment = PE_DEF_SECTION_ALIGNMENT;
       break;
     }
+  if (s != subsystem)
+    free ((char *) subsystem);
 }
 
 /* Convert EFI target to PEI target.  */
@@ -3902,7 +3969,8 @@ copy_main (int argc, char *argv[])
 
   /* If there is no destination file, or the source and destination files
      are the same, then create a temp and rename the result into the input.  */
-  if (output_filename == NULL || strcmp (input_filename, output_filename) == 0)
+  if (output_filename == NULL
+      || filename_cmp (input_filename, output_filename) == 0)
     tmpname = make_tempname (input_filename);
   else
     tmpname = output_filename;
This page took 0.025825 seconds and 4 git commands to generate.