OSDN Git Service

Add elfedit
authorhjl <hjl>
Thu, 7 Jan 2010 01:52:13 +0000 (01:52 +0000)
committerhjl <hjl>
Thu, 7 Jan 2010 01:52:13 +0000 (01:52 +0000)
binutils/

2010-01-06  H.J. Lu  <hongjiu.lu@intel.com>

PR binutils/11131
* Makefile.am (ELFEDIT_PROG): New.
(bin_PROGRAMS): Add $(ELFEDIT_PROG).
(CFILES): Add elfedit.c.
(elfedit_DEPENDENCIES): New.
(elfedit_SOURCES): Likewise.
(elfedit_LDADD): Likewise.
* Makefile.in: Regenerated.

* elfedit.c: New.

* doc/binutils.texi: Document elfedit.

* doc/Makefile.am (man_MANS): Add elfedit.1.
(elfedit.1): New.
* doc/Makefile.in: Regenerated.

binutils/testsuite/

2010-01-06  H.J. Lu  <hongjiu.lu@intel.com>

PR binutils/11131
* binutils-all/elfedit-1.d: New.
* binutils-all/elfedit.exp: Likewise.

* config/default.exp (ELFEDIT): New. Set if it doesn't exist.
(ELFEDITFLAGS): Likewise.

* lib/utils-lib.exp (run_dump_test): Support elfedit.

12 files changed:
binutils/ChangeLog
binutils/Makefile.am
binutils/Makefile.in
binutils/doc/Makefile.am
binutils/doc/Makefile.in
binutils/doc/binutils.texi
binutils/elfedit.c [new file with mode: 0644]
binutils/testsuite/ChangeLog
binutils/testsuite/binutils-all/elfedit-1.d [new file with mode: 0644]
binutils/testsuite/binutils-all/elfedit.exp [new file with mode: 0644]
binutils/testsuite/config/default.exp
binutils/testsuite/lib/utils-lib.exp

index ad9bdbd..d2c4b1e 100644 (file)
@@ -1,3 +1,22 @@
+2010-01-06  H.J. Lu  <hongjiu.lu@intel.com>
+
+       PR binutils/11131
+       * Makefile.am (ELFEDIT_PROG): New.
+       (bin_PROGRAMS): Add $(ELFEDIT_PROG).
+       (CFILES): Add elfedit.c.
+       (elfedit_DEPENDENCIES): New.
+       (elfedit_SOURCES): Likewise.
+       (elfedit_LDADD): Likewise.
+       * Makefile.in: Regenerated.
+
+       * elfedit.c: New.
+
+       * doc/binutils.texi: Document elfedit.
+
+       * doc/Makefile.am (man_MANS): Add elfedit.1.
+       (elfedit.1): New.
+       * doc/Makefile.in: Regenerated.
+
 2010-01-06  Tristan Gingold  <gingold@adacore.com>
 
        * nm.c (usage): Remove extra blanks.
index db7a773..873e568 100644 (file)
@@ -39,6 +39,8 @@ STRINGS_PROG=strings
 
 READELF_PROG=readelf
 
+ELFEDIT_PROG=elfedit
+
 # These should all be the same program too.
 SIZE_PROG=size
 NM_PROG=nm-new
@@ -58,7 +60,7 @@ DLLWRAP_PROG=dllwrap
 
 SRCONV_PROG=srconv$(EXEEXT) sysdump$(EXEEXT) coffdump$(EXEEXT)
 
-bin_PROGRAMS = $(SIZE_PROG) $(OBJDUMP_PROG) $(AR_PROG) $(STRINGS_PROG) $(RANLIB_PROG) $(OBJCOPY_PROG) @BUILD_NLMCONV@ @BUILD_SRCONV@ @BUILD_DLLTOOL@ @BUILD_WINDRES@ @BUILD_WINDMC@ $(ADDR2LINE_PROG) $(READELF_PROG) @BUILD_DLLWRAP@ @BUILD_INSTALL_MISC@
+bin_PROGRAMS = $(SIZE_PROG) $(OBJDUMP_PROG) $(AR_PROG) $(STRINGS_PROG) $(RANLIB_PROG) $(OBJCOPY_PROG) @BUILD_NLMCONV@ @BUILD_SRCONV@ @BUILD_DLLTOOL@ @BUILD_WINDRES@ @BUILD_WINDMC@ $(ADDR2LINE_PROG) $(READELF_PROG) $(ELFEDIT_PROG) @BUILD_DLLWRAP@ @BUILD_INSTALL_MISC@
 
 ## We need a special rule to install the programs which are built with
 ## -new, and to rename cxxfilt to c++filt.
@@ -100,7 +102,7 @@ CFILES = \
        rclex.c rdcoff.c rddbg.c readelf.c rename.c \
        resbin.c rescoff.c resrc.c resres.c \
        size.c srconv.c stabs.c strings.c sysdump.c \
-       unwind-ia64.c version.c \
+       unwind-ia64.c elfedit.c version.c \
        windres.c winduni.c wrstabs.c \
        windmc.c mclex.c
 
@@ -179,6 +181,7 @@ windres_DEPENDENCIES =   $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
 windmc_DEPENDENCIES =    $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
 addr2line_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
 readelf_DEPENDENCIES =   $(LIBINTL_DEP) $(LIBIBERTY)
+elfedit_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY)
 dllwrap_DEPENDENCIES =   $(LIBINTL_DEP) $(LIBIBERTY)
 
 LDADD = $(BFDLIB) $(LIBIBERTY) $(LIBINTL)
@@ -192,6 +195,9 @@ strings_SOURCES = strings.c $(BULIBS)
 readelf_SOURCES = readelf.c version.c unwind-ia64.c dwarf.c
 readelf_LDADD   = $(LIBINTL) $(LIBIBERTY)
 
+elfedit_SOURCES = elfedit.c version.c
+elfedit_LDADD = $(LIBINTL) $(LIBIBERTY)
+
 strip_new_SOURCES = objcopy.c is-strip.c rename.c $(WRITE_DEBUG_SRCS) $(BULIBS)
 
 nm_new_SOURCES = nm.c $(BULIBS)
index 5b29a02..8cc1746 100644 (file)
@@ -39,8 +39,8 @@ bin_PROGRAMS = $(am__EXEEXT_6) $(am__EXEEXT_7) $(am__EXEEXT_8) \
        $(am__EXEEXT_9) $(am__EXEEXT_10) $(am__EXEEXT_11) \
        @BUILD_NLMCONV@ @BUILD_SRCONV@ @BUILD_DLLTOOL@ @BUILD_WINDRES@ \
        @BUILD_WINDMC@ $(am__EXEEXT_12) $(am__EXEEXT_13) \
-       @BUILD_DLLWRAP@ @BUILD_INSTALL_MISC@ $(am__empty)
-noinst_PROGRAMS = $(am__EXEEXT_17) @BUILD_MISC@
+       $(am__EXEEXT_14) @BUILD_DLLWRAP@ @BUILD_INSTALL_MISC@
+noinst_PROGRAMS = $(am__EXEEXT_18) @BUILD_MISC@
 EXTRA_PROGRAMS = $(am__EXEEXT_1) srconv$(EXEEXT) sysdump$(EXEEXT) \
        coffdump$(EXEEXT) $(am__EXEEXT_2) $(am__EXEEXT_3) \
        $(am__EXEEXT_4) $(am__EXEEXT_5)
@@ -93,11 +93,12 @@ am__EXEEXT_10 = ranlib$(EXEEXT)
 am__EXEEXT_11 = objcopy$(EXEEXT)
 am__EXEEXT_12 = addr2line$(EXEEXT)
 am__EXEEXT_13 = readelf$(EXEEXT)
+am__EXEEXT_14 = elfedit$(EXEEXT)
 am__installdirs = "$(DESTDIR)$(bindir)"
-am__EXEEXT_14 = nm-new$(EXEEXT)
-am__EXEEXT_15 = strip-new$(EXEEXT)
-am__EXEEXT_16 = cxxfilt$(EXEEXT)
-am__EXEEXT_17 = $(am__EXEEXT_14) $(am__EXEEXT_15) $(am__EXEEXT_16)
+am__EXEEXT_15 = nm-new$(EXEEXT)
+am__EXEEXT_16 = strip-new$(EXEEXT)
+am__EXEEXT_17 = cxxfilt$(EXEEXT)
+am__EXEEXT_18 = $(am__EXEEXT_15) $(am__EXEEXT_16) $(am__EXEEXT_17)
 PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS)
 am__objects_1 = bucomm.$(OBJEXT) version.$(OBJEXT) filemode.$(OBJEXT)
 am_addr2line_OBJECTS = addr2line.$(OBJEXT) $(am__objects_1)
@@ -161,6 +162,8 @@ strip_new_LDADD = $(LDADD)
 am_sysdump_OBJECTS = sysdump.$(OBJEXT) $(am__objects_1)
 sysdump_OBJECTS = $(am_sysdump_OBJECTS)
 sysdump_LDADD = $(LDADD)
+am_elfedit_OBJECTS = elfedit.$(OBJEXT) version.$(OBJEXT)
+elfedit_OBJECTS = $(am_elfedit_OBJECTS)
 am_windmc_OBJECTS = windmc.$(OBJEXT) mcparse.$(OBJEXT) mclex.$(OBJEXT) \
        winduni.$(OBJEXT) $(am__objects_1)
 windmc_OBJECTS = $(am_windmc_OBJECTS)
@@ -197,7 +200,7 @@ SOURCES = $(addr2line_SOURCES) $(ar_SOURCES) $(EXTRA_ar_SOURCES) \
        $(objcopy_SOURCES) $(objdump_SOURCES) $(ranlib_SOURCES) \
        $(readelf_SOURCES) $(size_SOURCES) $(srconv_SOURCES) \
        $(strings_SOURCES) $(strip_new_SOURCES) $(sysdump_SOURCES) \
-       $(windmc_SOURCES) $(windres_SOURCES)
+       $(elfedit_SOURCES) $(windmc_SOURCES) $(windres_SOURCES)
 RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
        html-recursive info-recursive install-data-recursive \
        install-dvi-recursive install-exec-recursive \
@@ -392,6 +395,7 @@ OBJCOPY_PROG = objcopy
 STRIP_PROG = strip-new
 STRINGS_PROG = strings
 READELF_PROG = readelf
+ELFEDIT_PROG = elfedit
 
 # These should all be the same program too.
 SIZE_PROG = size
@@ -440,7 +444,7 @@ CFILES = \
        rclex.c rdcoff.c rddbg.c readelf.c rename.c \
        resbin.c rescoff.c resrc.c resres.c \
        size.c srconv.c stabs.c strings.c sysdump.c \
-       unwind-ia64.c version.c \
+       unwind-ia64.c elfedit.c version.c \
        windres.c winduni.c wrstabs.c \
        windmc.c mclex.c
 
@@ -496,6 +500,7 @@ windres_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
 windmc_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
 addr2line_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY) $(BFDLIB)
 readelf_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY)
+elfedit_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY)
 dllwrap_DEPENDENCIES = $(LIBINTL_DEP) $(LIBIBERTY)
 LDADD = $(BFDLIB) $(LIBIBERTY) $(LIBINTL)
 size_SOURCES = size.c $(BULIBS)
@@ -503,6 +508,8 @@ objcopy_SOURCES = objcopy.c not-strip.c rename.c $(WRITE_DEBUG_SRCS) $(BULIBS)
 strings_SOURCES = strings.c $(BULIBS)
 readelf_SOURCES = readelf.c version.c unwind-ia64.c dwarf.c
 readelf_LDADD = $(LIBINTL) $(LIBIBERTY)
+elfedit_SOURCES = elfedit.c version.c
+elfedit_LDADD = $(LIBINTL) $(LIBIBERTY)
 strip_new_SOURCES = objcopy.c is-strip.c rename.c $(WRITE_DEBUG_SRCS) $(BULIBS)
 nm_new_SOURCES = nm.c $(BULIBS)
 objdump_SOURCES = objdump.c dwarf.c prdbg.c $(DEBUG_SRCS) $(BULIBS)
@@ -718,6 +725,9 @@ strip-new$(EXEEXT): $(strip_new_OBJECTS) $(strip_new_DEPENDENCIES)
 sysdump$(EXEEXT): $(sysdump_OBJECTS) $(sysdump_DEPENDENCIES) 
        @rm -f sysdump$(EXEEXT)
        $(LINK) $(sysdump_OBJECTS) $(sysdump_LDADD) $(LIBS)
+elfedit$(EXEEXT): $(elfedit_OBJECTS) $(elfedit_DEPENDENCIES) 
+       @rm -f elfedit$(EXEEXT)
+       $(LINK) $(elfedit_OBJECTS) $(elfedit_LDADD) $(LIBS)
 mcparse.h: mcparse.c
        @if test ! -f $@; then \
          rm -f mcparse.c; \
@@ -793,6 +803,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strings.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sysdump.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unwind-ia64.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfedit.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/version.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/windmc.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/windres.Po@am__quote@
index bdd470d..a2295ca 100644 (file)
@@ -27,6 +27,7 @@ man_MANS = \
        size.1 \
        strings.1 \
        strip.1 \
+       elfedit.1 \
        windres.1 \
        windmc.1 \
        $(DEMANGLER_NAME).1
@@ -124,6 +125,13 @@ strip.1:   $(binutils_TEXI) $(binutils_TEXINFOS)
                mv -f $@.T$$$$ $@) || (rm -f $@.T$$$$ && exit 1)
        rm -f strip.pod
 
+elfedit.1:     $(binutils_TEXI) $(binutils_TEXINFOS)
+       touch $@
+       -$(TEXI2POD) $(MANCONF) -Delfedit < $(binutils_TEXI) > elfedit.pod
+       -($(POD2MAN) elfedit.pod | sed -e '/^.if n .na/d' > $@.T$$$$ && \
+               mv -f $@.T$$$$ $@) || (rm -f $@.T$$$$ && exit 1)
+       rm -f elfedit.pod
+
 windres.1:     $(binutils_TEXI) $(binutils_TEXINFOS)
        touch $@
        -$(TEXI2POD) $(MANCONF) -Dwindres < $(binutils_TEXI) > windres.pod
index 897e5d8..31f4dd3 100644 (file)
@@ -286,6 +286,7 @@ man_MANS = \
        size.1 \
        strings.1 \
        strip.1 \
+       elfedit.1 \
        windres.1 \
        windmc.1 \
        $(DEMANGLER_NAME).1
@@ -816,6 +817,13 @@ strip.1:   $(binutils_TEXI) $(binutils_TEXINFOS)
                mv -f $@.T$$$$ $@) || (rm -f $@.T$$$$ && exit 1)
        rm -f strip.pod
 
+elfedit.1:     $(binutils_TEXI) $(binutils_TEXINFOS)
+       touch $@
+       -$(TEXI2POD) $(MANCONF) -Delfedit < $(binutils_TEXI) > elfedit.pod
+       -($(POD2MAN) elfedit.pod | sed -e '/^.if n .na/d' > $@.T$$$$ && \
+               mv -f $@.T$$$$ $@) || (rm -f $@.T$$$$ && exit 1)
+       rm -f elfedit.pod
+
 windres.1:     $(binutils_TEXI) $(binutils_TEXINFOS)
        touch $@
        -$(TEXI2POD) $(MANCONF) -Dwindres < $(binutils_TEXI) > windres.pod
index fa4fa26..60ac2bd 100644 (file)
@@ -44,6 +44,7 @@ section entitled ``GNU Free Documentation License''.
 * size: (binutils)size.           List section sizes and total size.
 * strings: (binutils)strings.     List printable strings from files.
 * strip: (binutils)strip.         Discard symbols.
+* elfedit: (binutils)elfedit.     Update the ELF header of ELF files.
 * windmc: (binutils)windmc.      Generator for Windows message resources.
 * windres: (binutils)windres.    Manipulate Windows resources.
 @end direntry
@@ -111,6 +112,9 @@ List printable strings from files
 @item strip
 Discard symbols
 
+@item elfedit
+Update the ELF header of ELF files.
+
 @item c++filt
 Demangle encoded C++ symbols (on MS-DOS, this program is named
 @code{cxxfilt})
@@ -146,6 +150,7 @@ in the section entitled ``GNU Free Documentation License''.
 * size::                        List section sizes and total size
 * strings::                     List printable strings from files
 * strip::                       Discard symbols
+* elfedit::                     Update the ELF header of ELF files
 * c++filt::                    Filter to demangle encoded C++ symbols
 * cxxfilt: c++filt.             MS-DOS name for c++filt
 * addr2line::                  Convert addresses to file and line
@@ -2717,7 +2722,7 @@ the Info entries for @file{binutils}.
 @c man end
 @end ignore
 
-@node c++filt, addr2line, strip, Top
+@node c++filt, addr2line, elfedit, Top
 @chapter c++filt
 
 @kindex c++filt
@@ -4090,6 +4095,70 @@ objdump(1), and the Info entries for @file{binutils}.
 @c man end
 @end ignore
 
+@node elfedit
+@chapter elfedit
+
+@cindex Update ELF header
+@kindex elfedit
+
+@c man title elfedit Update the ELF header of ELF files.
+
+@smallexample
+@c man begin SYNOPSIS elfedit
+elfedit [@option{--input-mach=}@var{machine}]
+        @option{--output-machine=}@var{machine}
+        [@option{-v}|@option{--version}]
+        [@option{-h}|@option{--help}]
+        @var{elffile}@dots{}
+@c man end
+@end smallexample
+
+@c man begin DESCRIPTION elfedit
+
+@command{elfedit} updates the ELF header of ELF files.  The
+options control how and which fields in the ELF header should be
+updated.
+
+@var{elffile}@dots{} are the ELF files to be updated.  32-bit and
+64-bit ELF files are supported, as are archives containing ELF files.
+@c man end
+
+@c man begin OPTIONS elfedit
+
+The long and short forms of options, shown here as alternatives, are
+equivalent. The @option{--output-mach} option must be given.
+
+@table @env
+
+@itemx --input-mach=@var{machine}
+Only the input files with ELF machine type, @var{machine}, will be
+updated. If @option{--input-mach} isn't specified, any ELF file
+will be updated.
+
+The supported ELF machine types are, @var{L1OM} and @var{x86-64}.
+
+@itemx --output-mach=@var{machine}
+Change the ELF machine type in the ELF header to @var{machine}.  The
+supported ELF machine types are the same as @option{--input-mach}.
+
+@item -v
+@itemx --version
+Display the version number of @command{elfedit}.
+
+@item -h
+@itemx --help
+Display the command line options understood by @command{elfedit}.
+
+@end table
+
+@c man end
+
+@ignore
+@c man begin SEEALSO elfedit
+readelf(1), and the Info entries for @file{binutils}.
+@c man end
+@end ignore
+
 @node Common Options
 @chapter Common Options
 
diff --git a/binutils/elfedit.c b/binutils/elfedit.c
new file mode 100644 (file)
index 0000000..28e40be
--- /dev/null
@@ -0,0 +1,1110 @@
+/* elfedit.c -- Update the ELF header of an ELF format file
+   Copyright 2010
+   Free Software Foundation, Inc.
+
+   This file is part of GNU Binutils.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+   02110-1301, USA.  */
+\f
+#include "config.h"
+#include "sysdep.h"
+#include <assert.h>
+#include <sys/stat.h>
+
+#if __GNUC__ >= 2
+/* Define BFD64 here, even if our default architecture is 32 bit ELF
+   as this will allow us to read in and parse 64bit and 32bit ELF files.
+   Only do this if we believe that the compiler can support a 64 bit
+   data type.  For now we only rely on GCC being able to do this.  */
+#define BFD64
+#endif
+
+#include "bfd.h"
+#include "bucomm.h"
+
+#include "elf/common.h"
+#include "elf/external.h"
+#include "elf/internal.h"
+
+
+#include "aout/ar.h"
+
+#include "getopt.h"
+#include "libiberty.h"
+#include "safe-ctype.h"
+#include "filenames.h"
+
+char * program_name = "elfedit";
+static long archive_file_offset;
+static unsigned long archive_file_size;
+static Elf_Internal_Ehdr elf_header;
+static Elf32_External_Ehdr ehdr32;
+static Elf64_External_Ehdr ehdr64;
+static int input_elf_machine = -1;
+static int output_elf_machine = -1;
+static int input_elf_class = -1;
+
+#define streq(a,b)       (strcmp ((a), (b)) == 0)
+#define strneq(a,b,n)    (strncmp ((a), (b), (n)) == 0)
+#define const_strneq(a,b) (strncmp ((a), (b), sizeof (b) - 1) == 0)
+
+void
+non_fatal (const char *message, ...)
+{
+  va_list args;
+
+  va_start (args, message);
+  fprintf (stderr, _("%s: Error: "), program_name);
+  vfprintf (stderr, message, args);
+  va_end (args);
+}
+
+#define BYTE_GET(field)                byte_get (field, sizeof (field))
+#define BYTE_PUT(field, val)   byte_put (field, val, sizeof (field))
+
+static bfd_vma (*byte_get) (unsigned char *, int);
+static void (*byte_put) (unsigned char *, bfd_vma, int);
+
+static bfd_vma
+byte_get_little_endian (unsigned char *field, int size)
+{
+  switch (size)
+    {
+    case 1:
+      return *field;
+
+    case 2:
+      return  ((unsigned int) (field[0]))
+       |    (((unsigned int) (field[1])) << 8);
+
+    case 4:
+      return  ((unsigned long) (field[0]))
+       |    (((unsigned long) (field[1])) << 8)
+       |    (((unsigned long) (field[2])) << 16)
+       |    (((unsigned long) (field[3])) << 24);
+
+    case 8:
+      if (sizeof (bfd_vma) == 8)
+       return  ((bfd_vma) (field[0]))
+         |    (((bfd_vma) (field[1])) << 8)
+         |    (((bfd_vma) (field[2])) << 16)
+         |    (((bfd_vma) (field[3])) << 24)
+         |    (((bfd_vma) (field[4])) << 32)
+         |    (((bfd_vma) (field[5])) << 40)
+         |    (((bfd_vma) (field[6])) << 48)
+         |    (((bfd_vma) (field[7])) << 56);
+      else if (sizeof (bfd_vma) == 4)
+       /* We want to extract data from an 8 byte wide field and
+          place it into a 4 byte wide field.  Since this is a little
+          endian source we can just use the 4 byte extraction code.  */
+       return  ((unsigned long) (field[0]))
+         |    (((unsigned long) (field[1])) << 8)
+         |    (((unsigned long) (field[2])) << 16)
+         |    (((unsigned long) (field[3])) << 24);
+
+    default:
+      non_fatal (_("Unhandled data length: %d\n"), size);
+      abort ();
+    }
+}
+
+static bfd_vma
+byte_get_big_endian (unsigned char *field, int size)
+{
+  switch (size)
+    {
+    case 1:
+      return *field;
+
+    case 2:
+      return ((unsigned int) (field[1])) | (((int) (field[0])) << 8);
+
+    case 4:
+      return ((unsigned long) (field[3]))
+       |   (((unsigned long) (field[2])) << 8)
+       |   (((unsigned long) (field[1])) << 16)
+       |   (((unsigned long) (field[0])) << 24);
+
+    case 8:
+      if (sizeof (bfd_vma) == 8)
+       return ((bfd_vma) (field[7]))
+         |   (((bfd_vma) (field[6])) << 8)
+         |   (((bfd_vma) (field[5])) << 16)
+         |   (((bfd_vma) (field[4])) << 24)
+         |   (((bfd_vma) (field[3])) << 32)
+         |   (((bfd_vma) (field[2])) << 40)
+         |   (((bfd_vma) (field[1])) << 48)
+         |   (((bfd_vma) (field[0])) << 56);
+      else if (sizeof (bfd_vma) == 4)
+       {
+         /* Although we are extracing data from an 8 byte wide field,
+            we are returning only 4 bytes of data.  */
+         field += 4;
+         return ((unsigned long) (field[3]))
+           |   (((unsigned long) (field[2])) << 8)
+           |   (((unsigned long) (field[1])) << 16)
+           |   (((unsigned long) (field[0])) << 24);
+       }
+
+    default:
+      non_fatal (_("Unhandled data length: %d\n"), size);
+      abort ();
+    }
+}
+
+static void
+byte_put_little_endian (unsigned char * field, bfd_vma value, int size)
+{
+  switch (size)
+    {
+    case 8:
+      field[7] = (((value >> 24) >> 24) >> 8) & 0xff;
+      field[6] = ((value >> 24) >> 24) & 0xff;
+      field[5] = ((value >> 24) >> 16) & 0xff;
+      field[4] = ((value >> 24) >> 8) & 0xff;
+      /* Fall through.  */
+    case 4:
+      field[3] = (value >> 24) & 0xff;
+      field[2] = (value >> 16) & 0xff;
+      /* Fall through.  */
+    case 2:
+      field[1] = (value >> 8) & 0xff;
+      /* Fall through.  */
+    case 1:
+      field[0] = value & 0xff;
+      break;
+
+    default:
+      non_fatal (_("Unhandled data length: %d\n"), size);
+      abort ();
+    }
+}
+
+static void
+byte_put_big_endian (unsigned char * field, bfd_vma value, int size)
+{
+  switch (size)
+    {
+    case 8:
+      field[7] = value & 0xff;
+      field[6] = (value >> 8) & 0xff;
+      field[5] = (value >> 16) & 0xff;
+      field[4] = (value >> 24) & 0xff;
+      value >>= 16;
+      value >>= 16;
+      /* Fall through.  */
+    case 4:
+      field[3] = value & 0xff;
+      field[2] = (value >> 8) & 0xff;
+      value >>= 16;
+      /* Fall through.  */
+    case 2:
+      field[1] = value & 0xff;
+      value >>= 8;
+      /* Fall through.  */
+    case 1:
+      field[0] = value & 0xff;
+      break;
+
+    default:
+      non_fatal (_("Unhandled data length: %d\n"), size);
+      abort ();
+    }
+}
+
+static int
+update_elf_header (const char *file_name, FILE *file)
+{
+  int status;
+
+  if (elf_header.e_ident[EI_MAG0] != ELFMAG0
+      || elf_header.e_ident[EI_MAG1] != ELFMAG1
+      || elf_header.e_ident[EI_MAG2] != ELFMAG2
+      || elf_header.e_ident[EI_MAG3] != ELFMAG3)
+    {
+      non_fatal
+       (_("%s: Not an ELF file - wrong magic bytes at the start\n"),
+        file_name);
+      return 0;
+    }
+
+  if (elf_header.e_ident[EI_VERSION] != EV_CURRENT)
+    {
+      non_fatal
+       (_("%s: Unsupported EI_VERSION: %d is not %d\n"),
+        file_name, elf_header.e_ident[EI_VERSION],
+        EV_CURRENT);
+      return 0;
+    }
+
+  /* Skip if class doesn't match. */
+  if (input_elf_class == -1)
+    input_elf_class = elf_header.e_ident[EI_CLASS];
+  else
+  if (elf_header.e_ident[EI_CLASS] != input_elf_class)
+    {
+      non_fatal
+       (_("%s: Unmatched EI_CLASS: %d is not %d\n"),
+        file_name, elf_header.e_ident[EI_CLASS],
+        input_elf_class);
+      return 0;
+    }
+
+  /* Return if e_machine is the same as output_elf_machine.  */
+  if (output_elf_machine == elf_header.e_machine)
+    return 1;
+
+  /* Skip if e_machine doesn't match. */
+  if (input_elf_machine == -1)
+    input_elf_machine = elf_header.e_machine;
+  else if (elf_header.e_machine != input_elf_machine)
+    {
+      non_fatal
+       (_("%s: Unmatched e_machine: %d is not %d\n"),
+        file_name, elf_header.e_machine, input_elf_machine);
+      return 0;
+    }
+
+  /* Update e_machine.  */
+  switch (input_elf_class)
+    {
+    default:
+      /* We should never get here.  */
+      abort ();
+      break;
+    case ELFCLASS32:
+      BYTE_PUT (ehdr32.e_machine, output_elf_machine);
+      status = fwrite (&ehdr32, sizeof (ehdr32), 1, file) == 1;
+      break;
+    case ELFCLASS64:
+      BYTE_PUT (ehdr64.e_machine, output_elf_machine);
+      status = fwrite (&ehdr64, sizeof (ehdr64), 1, file) == 1;
+      break;
+    }
+
+  if (status != 1)
+    non_fatal (_("%s: Failed to update ELF header: %s\n"),
+              file_name, strerror (errno));
+
+  return status;
+}
+
+static int
+get_file_header (FILE * file)
+{
+  /* Read in the identity array.  */
+  if (fread (elf_header.e_ident, EI_NIDENT, 1, file) != 1)
+    return 0;
+
+  /* Determine how to read the rest of the header.  */
+  switch (elf_header.e_ident[EI_DATA])
+    {
+    default: /* fall through */
+    case ELFDATANONE: /* fall through */
+    case ELFDATA2LSB:
+      byte_get = byte_get_little_endian;
+      byte_put = byte_put_little_endian;
+      break;
+    case ELFDATA2MSB:
+      byte_get = byte_get_big_endian;
+      byte_put = byte_put_big_endian;
+      break;
+    }
+
+  /* Read in the rest of the header.  For now we only support 32 bit
+     and 64 bit ELF files.  */
+  switch (elf_header.e_ident[EI_CLASS])
+    {
+    default:
+      non_fatal (_("Unsupported EI_CLASS: %d\n"),
+                elf_header.e_ident[EI_CLASS]);
+      return 0;
+
+    case ELFCLASS32:
+      if (fread (ehdr32.e_type, sizeof (ehdr32) - EI_NIDENT,
+                1, file) != 1)
+       return 0;
+
+      elf_header.e_type      = BYTE_GET (ehdr32.e_type);
+      elf_header.e_machine   = BYTE_GET (ehdr32.e_machine);
+      elf_header.e_version   = BYTE_GET (ehdr32.e_version);
+      elf_header.e_entry     = BYTE_GET (ehdr32.e_entry);
+      elf_header.e_phoff     = BYTE_GET (ehdr32.e_phoff);
+      elf_header.e_shoff     = BYTE_GET (ehdr32.e_shoff);
+      elf_header.e_flags     = BYTE_GET (ehdr32.e_flags);
+      elf_header.e_ehsize    = BYTE_GET (ehdr32.e_ehsize);
+      elf_header.e_phentsize = BYTE_GET (ehdr32.e_phentsize);
+      elf_header.e_phnum     = BYTE_GET (ehdr32.e_phnum);
+      elf_header.e_shentsize = BYTE_GET (ehdr32.e_shentsize);
+      elf_header.e_shnum     = BYTE_GET (ehdr32.e_shnum);
+      elf_header.e_shstrndx  = BYTE_GET (ehdr32.e_shstrndx);
+
+      memcpy (&ehdr32, &elf_header, EI_NIDENT);
+      break;
+
+    case ELFCLASS64:
+      /* If we have been compiled with sizeof (bfd_vma) == 4, then
+        we will not be able to cope with the 64bit data found in
+        64 ELF files.  Detect this now and abort before we start
+        overwriting things.  */
+      if (sizeof (bfd_vma) < 8)
+       {
+         non_fatal (_("This executable has been built without support for a\n\
+64 bit data type and so it cannot process 64 bit ELF files.\n"));
+         return 0;
+       }
+
+      if (fread (ehdr64.e_type, sizeof (ehdr64) - EI_NIDENT,
+                1, file) != 1)
+       return 0;
+
+      elf_header.e_type      = BYTE_GET (ehdr64.e_type);
+      elf_header.e_machine   = BYTE_GET (ehdr64.e_machine);
+      elf_header.e_version   = BYTE_GET (ehdr64.e_version);
+      elf_header.e_entry     = BYTE_GET (ehdr64.e_entry);
+      elf_header.e_phoff     = BYTE_GET (ehdr64.e_phoff);
+      elf_header.e_shoff     = BYTE_GET (ehdr64.e_shoff);
+      elf_header.e_flags     = BYTE_GET (ehdr64.e_flags);
+      elf_header.e_ehsize    = BYTE_GET (ehdr64.e_ehsize);
+      elf_header.e_phentsize = BYTE_GET (ehdr64.e_phentsize);
+      elf_header.e_phnum     = BYTE_GET (ehdr64.e_phnum);
+      elf_header.e_shentsize = BYTE_GET (ehdr64.e_shentsize);
+      elf_header.e_shnum     = BYTE_GET (ehdr64.e_shnum);
+      elf_header.e_shstrndx  = BYTE_GET (ehdr64.e_shstrndx);
+
+      memcpy (&ehdr64, &elf_header, EI_NIDENT);
+      break;
+    }
+  return 1;
+}
+
+/* Process one ELF object file according to the command line options.
+   This file may actually be stored in an archive.  The file is
+   positioned at the start of the ELF object.  */
+
+static int
+process_object (const char *file_name, FILE *file)
+{
+  /* Rememeber where we are.  */
+  long offset = ftell (file);
+
+  if (! get_file_header (file))
+    {
+      non_fatal (_("%s: Failed to read ELF header\n"), file_name);
+      return 1;
+    }
+
+  /* Go to the position of the ELF header.  */
+  if (fseek (file, offset, SEEK_SET) != 0)
+    {
+      non_fatal (_("%s: Failed to seek to ELF header\n"), file_name);
+    }
+
+  if (! update_elf_header (file_name, file))
+    return 1;
+
+  return 0;
+}
+
+/* Return the path name for a proxy entry in a thin archive, adjusted relative
+   to the path name of the thin archive itself if necessary.  Always returns
+   a pointer to malloc'ed memory.  */
+
+static char *
+adjust_relative_path (const char *file_name, char * name, int name_len)
+{
+  char * member_file_name;
+  const char * base_name = lbasename (file_name);
+
+  /* This is a proxy entry for a thin archive member.
+     If the extended name table contains an absolute path
+     name, or if the archive is in the current directory,
+     use the path name as given.  Otherwise, we need to
+     find the member relative to the directory where the
+     archive is located.  */
+  if (IS_ABSOLUTE_PATH (name) || base_name == file_name)
+    {
+      member_file_name = malloc (name_len + 1);
+      if (member_file_name == NULL)
+        {
+          non_fatal (_("Out of memory\n"));
+          return NULL;
+        }
+      memcpy (member_file_name, name, name_len);
+      member_file_name[name_len] = '\0';
+    }
+  else
+    {
+      /* Concatenate the path components of the archive file name
+         to the relative path name from the extended name table.  */
+      size_t prefix_len = base_name - file_name;
+      member_file_name = malloc (prefix_len + name_len + 1);
+      if (member_file_name == NULL)
+        {
+          non_fatal (_("Out of memory\n"));
+          return NULL;
+        }
+      memcpy (member_file_name, file_name, prefix_len);
+      memcpy (member_file_name + prefix_len, name, name_len);
+      member_file_name[prefix_len + name_len] = '\0';
+    }
+  return member_file_name;
+}
+
+/* Structure to hold information about an archive file.  */
+
+struct archive_info
+{
+  char * file_name;                     /* Archive file name.  */
+  FILE * file;                          /* Open file descriptor.  */
+  unsigned long index_num;              /* Number of symbols in table.  */
+  unsigned long * index_array;          /* The array of member offsets.  */
+  char * sym_table;                     /* The symbol table.  */
+  unsigned long sym_size;               /* Size of the symbol table.  */
+  char * longnames;                     /* The long file names table.  */
+  unsigned long longnames_size;         /* Size of the long file names table.  */
+  unsigned long nested_member_origin;   /* Origin in the nested archive of the current member.  */
+  unsigned long next_arhdr_offset;      /* Offset of the next archive header.  */
+  bfd_boolean is_thin_archive;          /* TRUE if this is a thin archive.  */
+  struct ar_hdr arhdr;                  /* Current archive header.  */
+};
+
+/* Read the symbol table and long-name table from an archive.  */
+
+static int
+setup_archive (struct archive_info * arch, const char * file_name,
+              FILE * file, bfd_boolean is_thin_archive)
+{
+  size_t got;
+  unsigned long size;
+
+  arch->file_name = strdup (file_name);
+  arch->file = file;
+  arch->index_num = 0;
+  arch->index_array = NULL;
+  arch->sym_table = NULL;
+  arch->sym_size = 0;
+  arch->longnames = NULL;
+  arch->longnames_size = 0;
+  arch->nested_member_origin = 0;
+  arch->is_thin_archive = is_thin_archive;
+  arch->next_arhdr_offset = SARMAG;
+
+  /* Read the first archive member header.  */
+  if (fseek (file, SARMAG, SEEK_SET) != 0)
+    {
+      non_fatal (_("%s: failed to seek to first archive header\n"),
+                file_name);
+      return 1;
+    }
+  got = fread (&arch->arhdr, 1, sizeof arch->arhdr, file);
+  if (got != sizeof arch->arhdr)
+    {
+      if (got == 0)
+       return 0;
+
+      non_fatal (_("%s: failed to read archive header\n"), file_name);
+      return 1;
+    }
+
+  /* See if this is the archive symbol table.  */
+  if (const_strneq (arch->arhdr.ar_name, "/               ")
+      || const_strneq (arch->arhdr.ar_name, "/SYM64/         "))
+    {
+      size = strtoul (arch->arhdr.ar_size, NULL, 10);
+      size = size + (size & 1);
+
+      arch->next_arhdr_offset += sizeof arch->arhdr + size;
+
+      if (fseek (file, size, SEEK_CUR) != 0)
+       {
+         non_fatal (_("%s: failed to skip archive symbol table\n"),
+                    file_name);
+         return 1;
+       }
+
+      /* Read the next archive header.  */
+      got = fread (&arch->arhdr, 1, sizeof arch->arhdr, file);
+      if (got != sizeof arch->arhdr)
+       {
+         if (got == 0)
+            return 0;
+         non_fatal (_("%s: failed to read archive header following archive index\n"),
+                    file_name);
+         return 1;
+       }
+    }
+
+  if (const_strneq (arch->arhdr.ar_name, "//              "))
+    {
+      /* This is the archive string table holding long member names.  */
+      arch->longnames_size = strtoul (arch->arhdr.ar_size, NULL, 10);
+      arch->next_arhdr_offset += sizeof arch->arhdr + arch->longnames_size;
+
+      arch->longnames = malloc (arch->longnames_size);
+      if (arch->longnames == NULL)
+       {
+         non_fatal (_("Out of memory reading long symbol names in archive\n"));
+         return 1;
+       }
+
+      if (fread (arch->longnames, arch->longnames_size, 1, file) != 1)
+       {
+         free (arch->longnames);
+         arch->longnames = NULL;
+         non_fatal (_("%s: failed to read long symbol name string table\n")
+                    , file_name);
+         return 1;
+       }
+
+      if ((arch->longnames_size & 1) != 0)
+       getc (file);
+    }
+
+  return 0;
+}
+
+/* Release the memory used for the archive information.  */
+
+static void
+release_archive (struct archive_info * arch)
+{
+  if (arch->file_name != NULL)
+    free (arch->file_name);
+  if (arch->index_array != NULL)
+    free (arch->index_array);
+  if (arch->sym_table != NULL)
+    free (arch->sym_table);
+  if (arch->longnames != NULL)
+    free (arch->longnames);
+}
+
+/* Open and setup a nested archive, if not already open.  */
+
+static int
+setup_nested_archive (struct archive_info * nested_arch, char * member_file_name)
+{
+  FILE * member_file;
+
+  /* Have we already setup this archive?  */
+  if (nested_arch->file_name != NULL
+      && streq (nested_arch->file_name, member_file_name))
+    return 0;
+
+  /* Close previous file and discard cached information.  */
+  if (nested_arch->file != NULL)
+    fclose (nested_arch->file);
+  release_archive (nested_arch);
+
+  member_file = fopen (member_file_name, "r+b");
+  if (member_file == NULL)
+    return 1;
+  return setup_archive (nested_arch, member_file_name, member_file,
+                       FALSE);
+}
+
+static char *
+get_archive_member_name_at (struct archive_info *  arch,
+                           unsigned long          offset,
+                           struct archive_info *  nested_arch);
+
+/* Get the name of an archive member from the current archive header.
+   For simple names, this will modify the ar_name field of the current
+   archive header.  For long names, it will return a pointer to the
+   longnames table.  For nested archives, it will open the nested archive
+   and get the name recursively.  NESTED_ARCH is a single-entry cache so
+   we don't keep rereading the same information from a nested archive.  */
+
+static char *
+get_archive_member_name (struct archive_info *  arch,
+                         struct archive_info *  nested_arch)
+{
+  unsigned long j, k;
+
+  if (arch->arhdr.ar_name[0] == '/')
+    {
+      /* We have a long name.  */
+      char * endp;
+      char * member_file_name;
+      char * member_name;
+
+      arch->nested_member_origin = 0;
+      k = j = strtoul (arch->arhdr.ar_name + 1, &endp, 10);
+      if (arch->is_thin_archive && endp != NULL && * endp == ':')
+        arch->nested_member_origin = strtoul (endp + 1, NULL, 10);
+
+      while ((j < arch->longnames_size)
+             && (arch->longnames[j] != '\n')
+             && (arch->longnames[j] != '\0'))
+        j++;
+      if (arch->longnames[j-1] == '/')
+        j--;
+      arch->longnames[j] = '\0';
+
+      if (!arch->is_thin_archive || arch->nested_member_origin == 0)
+        return arch->longnames + k;
+
+      /* This is a proxy for a member of a nested archive.
+         Find the name of the member in that archive.  */
+      member_file_name = adjust_relative_path (arch->file_name,
+                                              arch->longnames + k,
+                                              j - k);
+      if (member_file_name != NULL
+          && setup_nested_archive (nested_arch, member_file_name) == 0
+          && (member_name = get_archive_member_name_at (nested_arch,
+                                                       arch->nested_member_origin,
+                                                       NULL)) != NULL)
+        {
+          free (member_file_name);
+          return member_name;
+        }
+      free (member_file_name);
+
+      /* Last resort: just return the name of the nested archive.  */
+      return arch->longnames + k;
+    }
+
+  /* We have a normal (short) name.  */
+  j = 0;
+  while ((arch->arhdr.ar_name[j] != '/') && (j < 16))
+    j++;
+  arch->arhdr.ar_name[j] = '\0';
+  return arch->arhdr.ar_name;
+}
+
+/* Get the name of an archive member at a given OFFSET within an
+   archive ARCH.  */
+
+static char *
+get_archive_member_name_at (struct archive_info * arch,
+                            unsigned long         offset,
+                           struct archive_info * nested_arch)
+{
+  size_t got;
+
+  if (fseek (arch->file, offset, SEEK_SET) != 0)
+    {
+      non_fatal (_("%s: failed to seek to next file name\n"),
+                arch->file_name);
+      return NULL;
+    }
+  got = fread (&arch->arhdr, 1, sizeof arch->arhdr, arch->file);
+  if (got != sizeof arch->arhdr)
+    {
+      non_fatal (_("%s: failed to read archive header\n"),
+                arch->file_name);
+      return NULL;
+    }
+  if (memcmp (arch->arhdr.ar_fmag, ARFMAG, 2) != 0)
+    {
+      non_fatal (_("%s: did not find a valid archive header\n"),
+                arch->file_name);
+      return NULL;
+    }
+
+  return get_archive_member_name (arch, nested_arch);
+}
+
+/* Construct a string showing the name of the archive member, qualified
+   with the name of the containing archive file.  For thin archives, we
+   use square brackets to denote the indirection.  For nested archives,
+   we show the qualified name of the external member inside the square
+   brackets (e.g., "thin.a[normal.a(foo.o)]").  */
+
+static char *
+make_qualified_name (struct archive_info * arch,
+                     struct archive_info * nested_arch,
+                     char * member_name)
+{
+  size_t len;
+  char * name;
+
+  len = strlen (arch->file_name) + strlen (member_name) + 3;
+  if (arch->is_thin_archive && arch->nested_member_origin != 0)
+    len += strlen (nested_arch->file_name) + 2;
+
+  name = malloc (len);
+  if (name == NULL)
+    {
+      non_fatal (_("Out of memory\n"));
+      return NULL;
+    }
+
+  if (arch->is_thin_archive && arch->nested_member_origin != 0)
+    snprintf (name, len, "%s[%s(%s)]", arch->file_name, nested_arch->file_name, member_name);
+  else if (arch->is_thin_archive)
+    snprintf (name, len, "%s[%s]", arch->file_name, member_name);
+  else
+    snprintf (name, len, "%s(%s)", arch->file_name, member_name);
+
+  return name;
+}
+
+/* Process an ELF archive.
+   On entry the file is positioned just after the ARMAG string.  */
+
+static int
+process_archive (const char * file_name, FILE * file,
+                bfd_boolean is_thin_archive)
+{
+  struct archive_info arch;
+  struct archive_info nested_arch;
+  size_t got;
+  size_t file_name_size;
+  int ret;
+
+  /* The ARCH structure is used to hold information about this archive.  */
+  arch.file_name = NULL;
+  arch.file = NULL;
+  arch.index_array = NULL;
+  arch.sym_table = NULL;
+  arch.longnames = NULL;
+
+  /* The NESTED_ARCH structure is used as a single-item cache of information
+     about a nested archive (when members of a thin archive reside within
+     another regular archive file).  */
+  nested_arch.file_name = NULL;
+  nested_arch.file = NULL;
+  nested_arch.index_array = NULL;
+  nested_arch.sym_table = NULL;
+  nested_arch.longnames = NULL;
+
+  if (setup_archive (&arch, file_name, file, is_thin_archive) != 0)
+    {
+      ret = 1;
+      goto out;
+    }
+
+  file_name_size = strlen (file_name);
+  ret = 0;
+
+  while (1)
+    {
+      char * name;
+      size_t namelen;
+      char * qualified_name;
+
+      /* Read the next archive header.  */
+      if (fseek (file, arch.next_arhdr_offset, SEEK_SET) != 0)
+        {
+          non_fatal (_("%s: failed to seek to next archive header\n"),
+                    file_name);
+          return 1;
+        }
+      got = fread (&arch.arhdr, 1, sizeof arch.arhdr, file);
+      if (got != sizeof arch.arhdr)
+        {
+          if (got == 0)
+           break;
+          non_fatal (_("%s: failed to read archive header\n"),
+                    file_name);
+          ret = 1;
+          break;
+        }
+      if (memcmp (arch.arhdr.ar_fmag, ARFMAG, 2) != 0)
+        {
+          non_fatal (_("%s: did not find a valid archive header\n"),
+                    arch.file_name);
+          ret = 1;
+          break;
+        }
+
+      arch.next_arhdr_offset += sizeof arch.arhdr;
+
+      archive_file_size = strtoul (arch.arhdr.ar_size, NULL, 10);
+      if (archive_file_size & 01)
+        ++archive_file_size;
+
+      name = get_archive_member_name (&arch, &nested_arch);
+      if (name == NULL)
+       {
+         non_fatal (_("%s: bad archive file name\n"), file_name);
+         ret = 1;
+         break;
+       }
+      namelen = strlen (name);
+
+      qualified_name = make_qualified_name (&arch, &nested_arch, name);
+      if (qualified_name == NULL)
+       {
+         non_fatal (_("%s: bad archive file name\n"), file_name);
+         ret = 1;
+         break;
+       }
+
+      if (is_thin_archive && arch.nested_member_origin == 0)
+        {
+          /* This is a proxy for an external member of a thin archive.  */
+          FILE *member_file;
+          char *member_file_name = adjust_relative_path (file_name,
+                                                        name, namelen);
+          if (member_file_name == NULL)
+            {
+              ret = 1;
+              break;
+            }
+
+          member_file = fopen (member_file_name, "r+b");
+          if (member_file == NULL)
+            {
+              non_fatal (_("Input file '%s' is not readable\n"),
+                        member_file_name);
+              free (member_file_name);
+              ret = 1;
+              break;
+            }
+
+          archive_file_offset = arch.nested_member_origin;
+
+          ret |= process_object (qualified_name, member_file);
+
+          fclose (member_file);
+          free (member_file_name);
+        }
+      else if (is_thin_archive)
+        {
+          /* This is a proxy for a member of a nested archive.  */
+          archive_file_offset = arch.nested_member_origin + sizeof arch.arhdr;
+
+          /* The nested archive file will have been opened and setup by
+             get_archive_member_name.  */
+          if (fseek (nested_arch.file, archive_file_offset,
+                    SEEK_SET) != 0)
+            {
+              non_fatal (_("%s: failed to seek to archive member\n"),
+                        nested_arch.file_name);
+              ret = 1;
+              break;
+            }
+
+          ret |= process_object (qualified_name, nested_arch.file);
+        }
+      else
+        {
+          archive_file_offset = arch.next_arhdr_offset;
+          arch.next_arhdr_offset += archive_file_size;
+
+          ret |= process_object (qualified_name, file);
+        }
+
+      free (qualified_name);
+    }
+
+ out:
+  if (nested_arch.file != NULL)
+    fclose (nested_arch.file);
+  release_archive (&nested_arch);
+  release_archive (&arch);
+
+  return ret;
+}
+
+static int
+check_file (const char *file_name, struct stat *statbuf_p)
+{
+  struct stat statbuf;
+
+  if (statbuf_p == NULL)
+    statbuf_p = &statbuf;
+
+  if (stat (file_name, statbuf_p) < 0)
+    {
+      if (errno == ENOENT)
+       non_fatal (_("'%s': No such file\n"), file_name);
+      else
+       non_fatal (_("Could not locate '%s'.  System error message: %s\n"),
+                  file_name, strerror (errno));
+      return 1;
+    }
+
+  if (! S_ISREG (statbuf_p->st_mode))
+    {
+      non_fatal (_("'%s' is not an ordinary file\n"), file_name);
+      return 1;
+    }
+
+  return 0;
+}
+
+static int
+process_file (const char *file_name)
+{
+  FILE * file;
+  char armag[SARMAG];
+  int ret;
+
+  if (check_file (file_name, NULL))
+    return 1;
+
+  file = fopen (file_name, "r+b");
+  if (file == NULL)
+    {
+      non_fatal (_("Input file '%s' is not readable\n"), file_name);
+      return 1;
+    }
+
+  if (fread (armag, SARMAG, 1, file) != 1)
+    {
+      non_fatal (_("%s: Failed to read file's magic number\n"),
+                file_name);
+      fclose (file);
+      return 1;
+    }
+
+  if (memcmp (armag, ARMAG, SARMAG) == 0)
+    ret = process_archive (file_name, file, FALSE);
+  else if (memcmp (armag, ARMAGT, SARMAG) == 0)
+    ret = process_archive (file_name, file, TRUE);
+  else
+    {
+      rewind (file);
+      archive_file_size = archive_file_offset = 0;
+      ret = process_object (file_name, file);
+    }
+
+  fclose (file);
+
+  return ret;
+}
+
+/* Return EM_XXX for a machine string, MACH.  */
+
+static int
+elf_machine (const char *mach)
+{
+  if (strcasecmp (mach, "l1om") == 0)
+    return EM_L1OM;
+  if (strcasecmp (mach, "x86_64") == 0)
+    return EM_X86_64;
+  if (strcasecmp (mach, "x86-64") == 0)
+    return EM_X86_64;
+  if (strcasecmp (mach, "none") == 0)
+    return EM_NONE;
+
+  non_fatal (_("Unknown machine type: %s\n"), mach);
+
+  return -1;
+}
+
+/* Return ELF class for a machine type, MACH.  */
+
+static int
+elf_class (int mach)
+{
+  switch (mach)
+    {
+    case EM_L1OM:
+    case EM_X86_64:
+      return ELFCLASS64;
+    case EM_NONE:
+      return ELFCLASSNONE;
+    default:
+      non_fatal (_("Unknown machine type: %d\n"), mach);
+      return -1;
+    }
+}
+
+enum command_line_switch
+  {
+    OPTION_INPUT_MACH = 150,
+    OPTION_OUTPUT_MACH
+  };
+
+static struct option options[] =
+{
+  {"input-mach",       required_argument, 0, OPTION_INPUT_MACH},
+  {"output-mach",      required_argument, 0, OPTION_OUTPUT_MACH},
+  {"version",          no_argument, 0, 'v'},
+  {"help",             no_argument, 0, 'h'},
+  {0,                  no_argument, 0, 0}
+};
+
+static void
+usage (FILE *stream, int exit_status)
+{
+  fprintf (stream, _("Usage: %s [option(s)] --output-mach <machine> elffile(s)\n"),
+          program_name);
+  fprintf (stream, _(" Update the ELF header of ELF files\n"));
+  fprintf (stream, _(" The options are:\n"));
+  fprintf (stream, _("\
+  --input-mach <machine>      Set input machine type to <machine>\n\
+  --output-mach <machine>     Set output machine type to <machine>\n\
+  -h --help                   Display this information\n\
+  -v --version                Display the version number of %s\n\
+"),
+          program_name);
+  if (REPORT_BUGS_TO[0] && exit_status == 0)
+    fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO);
+  exit (exit_status);
+}
+
+int
+main (int argc, char ** argv)
+{
+  int c, status;
+
+#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
+  setlocale (LC_MESSAGES, "");
+#endif
+#if defined (HAVE_SETLOCALE)
+  setlocale (LC_CTYPE, "");
+#endif
+  bindtextdomain (PACKAGE, LOCALEDIR);
+  textdomain (PACKAGE);
+
+  expandargv (&argc, &argv);
+
+  while ((c = getopt_long (argc, argv, "hv",
+                          options, (int *) 0)) != EOF)
+    {
+      switch (c)
+       {
+       case OPTION_INPUT_MACH:
+         input_elf_machine = elf_machine (optarg);
+         if (input_elf_machine < 0)
+           return 1;
+         input_elf_class = elf_class (input_elf_machine);
+         if (input_elf_class < 0)
+           return 1;
+         break;
+
+       case OPTION_OUTPUT_MACH:
+         output_elf_machine = elf_machine (optarg);
+         if (output_elf_machine < 0)
+           return 1;
+         break;
+
+       case 'h':
+         usage (stdout, 0);
+
+       case 'v':
+         print_version (program_name);
+         break;
+
+       default:
+         usage (stderr, 1);
+       }
+    }
+
+  if (optind == argc || output_elf_machine == -1)
+    usage (stderr, 1);
+
+  status = 0;
+  while (optind < argc)
+    status |= process_file (argv[optind++]);
+
+  return status;
+}
index 3001daf..bd066e1 100644 (file)
@@ -1,3 +1,14 @@
+2010-01-06  H.J. Lu  <hongjiu.lu@intel.com>
+
+       PR binutils/11131
+       * binutils-all/elfedit-1.d: New.
+       * binutils-all/elfedit.exp: Likewise.
+
+       * config/default.exp (ELFEDIT): New. Set if it doesn't exist.
+       (ELFEDITFLAGS): Likewise.
+
+       * lib/utils-lib.exp (run_dump_test): Support elfedit.
+
 2009-10-28  Kai Tietz <kai.tietz@onevision.com>
 
        * binutils-all/dlltool.exp: Add tests for --no-leading-underscore
diff --git a/binutils/testsuite/binutils-all/elfedit-1.d b/binutils/testsuite/binutils-all/elfedit-1.d
new file mode 100644 (file)
index 0000000..3459315
--- /dev/null
@@ -0,0 +1,16 @@
+#PROG: elfedit
+#elfedit: --output-mach l1om
+#source: empty.s
+#readelf: -h
+#name: Update ELF header 1
+#target: x86_64-*-*
+
+#...
+ELF Header:
+  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
+  Class:                             ELF64
+  Data:                              2's complement, little endian
+  Version:                           1 \(current\)
+#...
+  Machine:                           Intel L1OM
+#...
diff --git a/binutils/testsuite/binutils-all/elfedit.exp b/binutils/testsuite/binutils-all/elfedit.exp
new file mode 100644 (file)
index 0000000..d43c31a
--- /dev/null
@@ -0,0 +1,31 @@
+#   Copyright 2010 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
+
+# Exclude non-ELF targets.
+if ![is_elf_format] {
+    verbose "$ELFEDIT is only intended for ELF targets" 2
+    return
+}
+
+if ![is_remote host] {
+    set tempfile tmpdir/bintest.o
+    set copyfile tmpdir/bintest
+} else {
+    set tempfile [remote_download host tmpdir/bintest.o]
+    set copyfile bintest
+}
+
+run_dump_test "elfedit-1"
index f3fd624..01fd8cc 100644 (file)
@@ -61,6 +61,12 @@ if ![info exists READELF] then {
 if ![info exists READELFFLAGS] then {
     set READELFFLAGS ""
 }
+if ![info exists ELFEDIT] then {
+    set ELFEDIT [findfile $base_dir/elfedit]
+}
+if ![info exists ELFEDITFLAGS] then {
+    set ELFEDITFLAGS ""
+}
 if ![info exists WINDRES] then {
     set WINDRES [findfile $base_dir/windres]
 }
index 9881f01..393aae8 100644 (file)
@@ -281,6 +281,7 @@ proc run_dump_test { name {extra_options {}} } {
     global subdir srcdir
     global OBJDUMP NM OBJCOPY READELF STRIP
     global OBJDUMPFLAGS NMFLAGS OBJCOPYFLAGS READELFFLAGS STRIPFLAGS
+    global ELFEDIT ELFEDITFLAGS
     global host_triplet
     global env
     global copyfile
@@ -309,6 +310,7 @@ proc run_dump_test { name {extra_options {}} } {
     set opts(size) {}
     set opts(strings) {}
     set opts(name) {}
+    set opts(elfedit) {}
     set opts(PROG) {}
     set opts(DUMPPROG) {}
     set opts(source) {}
@@ -372,6 +374,7 @@ proc run_dump_test { name {extra_options {}} } {
            set destopt "-o"
        }
        strings { set program strings }
+       elfedit { set program elfedit }
        default {
            perror "unrecognized program option $opts(PROG) in $file.d"
            unresolved $testname