From 7296d9338774c74e5a525f0c8f31c20f367997f5 Mon Sep 17 00:00:00 2001
From: Doug Kwan <dougkwan@google.com>
Date: Wed, 7 Apr 2010 21:42:22 +0000
Subject: [PATCH] 2010-04-07  Doug Kwan  <dougkwan@google.com>

	* arm.cc: Replace "endianity" with "endianness" in comments.
	(Arm_exidx_cantunwind): Ditto.
	(Arm_relobj::Arm_relobj): Initialize merge_flags_and_attribures.
	(Arm_relobj::merge_flags_and_attributes): New method.
	(Arm_relobj::merge_flags_and_attributes_): New data member.
	(Arm_exidx_cantunwind::do_fixed_endian_write): Fix formatting.
	(Arm_relobj::scan_sections_for_stubs): Ditto.
	(Arm_relobj::do_read_symbols): Check to see if we really want to
	merge processor-specific flags and attributes.  Exit early if
	an object is empty except for section names and the undefined symbol.
	(Target_arm::do_finalize_sections): Move check for ELF format to
	Arm_relobj::do_read_symbols.  Merge processor specific flags and
	attributes from a regular object only when we have determined that
	it is aapropriate.  Do not create an .ARM.attributes section in
	output if there is no regular input object.
	(Target_arm::merge_processor_specific_flags): Check
	--warn-mismatch before printing any error.
	(Target_arm::merge_object_attributes): Ditto.
	* gold.cc (queue_middle_tasks): Handle the case in which there is
	no regular object in input.
	* options.cc (General_options::parse_EB): New method.
	(General_options::parse_EL): Same.
	(General_options::General_options): Initialize endianness_.
	* options.h (-EB, -EL, -no-pipeline-knowledge, -p, --warn-mismatch):
	New options.
	(General_options::Endianness): New enum.
	(General_options::endianness): New method.
	(General_options::endianness_): New data member.
	* parameters.cc (Parameters::set_options): Check target endianness.
	(Parameters::set_target_once): Ditto.
	(Parameters::check_target_endianness): New method.
	(parameters_force_valid_target): If either -EL or -EB is specified,
	use it to define endianness of default target.
	* parameters.h (Parameters::check_target_endianness): New method
	declaration.
	* target.h (class Target): Change "endianity" to "endianness"
	in comments.
---
 gold/ChangeLog     |  40 +++++++++++++
 gold/arm.cc        | 136 +++++++++++++++++++++++++++++++--------------
 gold/gold.cc       |  20 +++++--
 gold/options.cc    |  15 ++++-
 gold/options.h     |  28 ++++++++++
 gold/parameters.cc |  38 ++++++++++++-
 gold/parameters.h  |   3 +
 gold/target.h      |   4 +-
 8 files changed, 233 insertions(+), 51 deletions(-)

diff --git a/gold/ChangeLog b/gold/ChangeLog
index 6c3f9e1d06e..e1e126abf6d 100644
--- a/gold/ChangeLog
+++ b/gold/ChangeLog
@@ -1,3 +1,43 @@
+2010-04-07  Doug Kwan  <dougkwan@google.com>
+
+	* arm.cc: Replace "endianity" with "endianness" in comments.
+	(Arm_exidx_cantunwind): Ditto.
+	(Arm_relobj::Arm_relobj): Initialize merge_flags_and_attribures.
+	(Arm_relobj::merge_flags_and_attributes): New method.
+	(Arm_relobj::merge_flags_and_attributes_): New data member.
+	(Arm_exidx_cantunwind::do_fixed_endian_write): Fix formatting.
+	(Arm_relobj::scan_sections_for_stubs): Ditto.
+	(Arm_relobj::do_read_symbols): Check to see if we really want to
+	merge processor-specific flags and attributes.  Exit early if
+	an object is empty except for section names and the undefined symbol.
+	(Target_arm::do_finalize_sections): Move check for ELF format to
+	Arm_relobj::do_read_symbols.  Merge processor specific flags and
+	attributes from a regular object only when we have determined that
+	it is aapropriate.  Do not create an .ARM.attributes section in
+	output if there is no regular input object.
+	(Target_arm::merge_processor_specific_flags): Check
+	--warn-mismatch before printing any error.
+	(Target_arm::merge_object_attributes): Ditto.
+	* gold.cc (queue_middle_tasks): Handle the case in which there is
+	no regular object in input.
+	* options.cc (General_options::parse_EB): New method.
+	(General_options::parse_EL): Same.
+	(General_options::General_options): Initialize endianness_.
+	* options.h (-EB, -EL, -no-pipeline-knowledge, -p, --warn-mismatch):
+	New options.
+	(General_options::Endianness): New enum.
+	(General_options::endianness): New method.
+	(General_options::endianness_): New data member.
+	* parameters.cc (Parameters::set_options): Check target endianness.
+	(Parameters::set_target_once): Ditto.
+	(Parameters::check_target_endianness): New method.
+	(parameters_force_valid_target): If either -EL or -EB is specified,
+	use it to define endianness of default target.
+	* parameters.h (Parameters::check_target_endianness): New method
+	declaration.
+	* target.h (class Target): Change "endianity" to "endianness"
+	in comments.
+
 2010-04-07  Ralf Wildenhues  <Ralf.Wildenhues@gmx.de>
 
 	* configure.ac (AM_INIT_AUTOMAKE): Add option no-dist.
diff --git a/gold/arm.cc b/gold/arm.cc
index 0f9f1bd1cc1..c2ac5a014e4 100644
--- a/gold/arm.cc
+++ b/gold/arm.cc
@@ -602,7 +602,7 @@ class Reloc_stub : public Stub
     // Otherwise, this points a relobj.  We used the unsized and target
     // independent Symbol and Relobj classes instead of Sized_symbol<32> and  
     // Arm_relobj.  This is done to avoid making the stub class a template
-    // as most of the stub machinery is endianity-neutral.  However, it
+    // as most of the stub machinery is endianness-neutral.  However, it
     // may require a bit of casting done by users of this class.
     union
     {
@@ -1065,7 +1065,7 @@ class Arm_exidx_cantunwind : public Output_section_data
   }
 
  private:
-  // Implement do_write for a given endianity.
+  // Implement do_write for a given endianness.
   template<bool big_endian>
   void inline
   do_fixed_endian_write(Output_file*);
@@ -1426,7 +1426,8 @@ class Arm_relobj : public Sized_relobj<32, big_endian>
       stub_tables_(), local_symbol_is_thumb_function_(),
       attributes_section_data_(NULL), mapping_symbols_info_(),
       section_has_cortex_a8_workaround_(NULL), exidx_section_map_(),
-      output_local_symbol_count_needs_update_(false)
+      output_local_symbol_count_needs_update_(false),
+      merge_flags_and_attributes_(true)
   { }
 
   ~Arm_relobj()
@@ -1565,6 +1566,11 @@ class Arm_relobj : public Sized_relobj<32, big_endian>
   void
   update_output_local_symbol_count();
 
+  // Whether we want to merge processor-specific flags and attributes.
+  bool
+  merge_flags_and_attributes() const
+  { return this->merge_flags_and_attributes_; }
+  
  protected:
   // Post constructor setup.
   void
@@ -1665,6 +1671,9 @@ class Arm_relobj : public Sized_relobj<32, big_endian>
   Exidx_section_map exidx_section_map_;
   // Whether output local symbol count needs updating.
   bool output_local_symbol_count_needs_update_;
+  // Whether we merge processor flags and attributes of this object to
+  // output.
+  bool merge_flags_and_attributes_;
 };
 
 // Arm_dynobj class.
@@ -4124,7 +4133,7 @@ Stub_template::Stub_template(
 
 // Stub methods.
 
-// Template to implement do_write for a specific target endianity.
+// Template to implement do_write for a specific target endianness.
 
 template<bool big_endian>
 void inline
@@ -4969,7 +4978,7 @@ Arm_input_section<big_endian>::do_reset_address_and_file_offset()
 
 // Arm_exidx_cantunwind methods.
 
-// Write this to Output file OF for a fixed endianity.
+// Write this to Output file OF for a fixed endianness.
 
 template<bool big_endian>
 void
@@ -4990,7 +4999,7 @@ Arm_exidx_cantunwind::do_fixed_endian_write(Output_file* of)
   Arm_address output_offset =
     arm_relobj->get_output_section_offset(this->shndx_);
   Arm_address section_start;
-  if(output_offset != Arm_relobj<big_endian>::invalid_address)
+  if (output_offset != Arm_relobj<big_endian>::invalid_address)
     section_start = os->address() + output_offset;
   else
     {
@@ -5946,7 +5955,7 @@ Arm_relobj<big_endian>::scan_sections_for_stubs(
 	  unsigned int index = this->adjust_shndx(shdr.get_sh_info());
 	  Arm_address output_offset = this->get_output_section_offset(index);
 	  Arm_address output_address;
-	  if(output_offset != invalid_address)
+	  if (output_offset != invalid_address)
 	    output_address = out_sections[index]->address() + output_offset;
 	  else
 	    {
@@ -6327,6 +6336,16 @@ Arm_relobj<big_endian>::do_read_symbols(Read_symbols_data* sd)
   // Call parent class to read symbol information.
   Sized_relobj<32, big_endian>::do_read_symbols(sd);
 
+  // If this input file is a binary file, it has no processor
+  // specific flags and attributes section.
+  Input_file::Format format = this->input_file()->format();
+  if (format != Input_file::FORMAT_ELF)
+    {
+      gold_assert(format == Input_file::FORMAT_BINARY);
+      this->merge_flags_and_attributes_ = false;
+      return;
+    }
+
   // Read processor-specific flags in ELF file header.
   const unsigned char* pehdr = this->get_view(elfcpp::file_header_offset,
 					      elfcpp::Elf_sizes<32>::ehdr_size,
@@ -6340,9 +6359,27 @@ Arm_relobj<big_endian>::do_read_symbols(Read_symbols_data* sd)
   const size_t shdr_size = elfcpp::Elf_sizes<32>::shdr_size;
   const unsigned char* pshdrs = sd->section_headers->data();
   const unsigned char *ps = pshdrs + shdr_size;
+  bool must_merge_flags_and_attributes = false;
   for (unsigned int i = 1; i < this->shnum(); ++i, ps += shdr_size)
     {
       elfcpp::Shdr<32, big_endian> shdr(ps);
+
+      // Sometimes an object has no contents except the section name string
+      // table and an empty symbol table with the undefined symbol.  We
+      // don't want to merge processor-specific flags from such an object.
+      if (shdr.get_sh_type() == elfcpp::SHT_SYMTAB)
+	{
+	  // Symbol table is not empty.
+	  const elfcpp::Elf_types<32>::Elf_WXword sym_size =
+	     elfcpp::Elf_sizes<32>::sym_size;
+	  if (shdr.get_sh_size() > sym_size)
+	    must_merge_flags_and_attributes = true;
+	}
+      else if (shdr.get_sh_type() != elfcpp::SHT_STRTAB)
+	// If this is neither an empty symbol table nor a string table,
+	// be conservative.
+	must_merge_flags_and_attributes = true;
+
       if (shdr.get_sh_type() == elfcpp::SHT_ARM_ATTRIBUTES)
 	{
      	  gold_assert(this->attributes_section_data_ == NULL);
@@ -6367,6 +6404,13 @@ Arm_relobj<big_endian>::do_read_symbols(Read_symbols_data* sd)
 	}
     }
 
+  // This is rare.
+  if (!must_merge_flags_and_attributes)
+    {
+      this->merge_flags_and_attributes_ = false;
+      return;
+    }
+
   // Some tools are broken and they do not set the link of EXIDX sections. 
   // We look at the first relocation to figure out the linked sections.
   if (!deferred_exidx_sections.empty())
@@ -7941,23 +7985,16 @@ Target_arm<big_endian>::do_finalize_sections(
        p != input_objects->relobj_end();
        ++p)
     {
-      // If this input file is a binary file, it has no processor
-      // specific flags and attributes section.
-      Input_file::Format format = (*p)->input_file()->format();
-      if (format != Input_file::FORMAT_ELF)
-	{
-	  gold_assert(format == Input_file::FORMAT_BINARY);
-	  continue;
-	}
-
       Arm_relobj<big_endian>* arm_relobj =
 	Arm_relobj<big_endian>::as_arm_relobj(*p);
-      this->merge_processor_specific_flags(
-	  arm_relobj->name(),
-	  arm_relobj->processor_specific_flags());
-      this->merge_object_attributes(arm_relobj->name().c_str(),
-				    arm_relobj->attributes_section_data());
-
+      if (arm_relobj->merge_flags_and_attributes())
+	{
+	  this->merge_processor_specific_flags(
+	      arm_relobj->name(),
+	      arm_relobj->processor_specific_flags());
+	  this->merge_object_attributes(arm_relobj->name().c_str(),
+					arm_relobj->attributes_section_data());
+	}
     } 
 
   for (Input_objects::Dynobj_iterator p = input_objects->dynobj_begin();
@@ -8046,13 +8083,17 @@ Target_arm<big_endian>::do_finalize_sections(
 	}
     }
 
-  // Create an .ARM.attributes section if there is not one already.
-  Output_attributes_section_data* attributes_section =
-    new Output_attributes_section_data(*this->attributes_section_data_);
-  layout->add_output_section_data(".ARM.attributes",
-				  elfcpp::SHT_ARM_ATTRIBUTES, 0,
-				  attributes_section, false, false, false,
-				  false);
+  // Create an .ARM.attributes section unless we have no regular input
+  // object.  In that case the output will be empty.
+  if (input_objects->number_of_relobjs() != 0)
+    {
+      Output_attributes_section_data* attributes_section =
+      new Output_attributes_section_data(*this->attributes_section_data_);
+      layout->add_output_section_data(".ARM.attributes",
+				      elfcpp::SHT_ARM_ATTRIBUTES, 0,
+				      attributes_section, false, false, false,
+				      false);
+    }
 }
 
 // Return whether a direct absolute static relocation needs to be applied.
@@ -8970,7 +9011,8 @@ Target_arm<big_endian>::merge_processor_specific_flags(
       // Complain about various flag mismatches.
       elfcpp::Elf_Word version1 = elfcpp::arm_eabi_version(flags);
       elfcpp::Elf_Word version2 = elfcpp::arm_eabi_version(out_flags);
-      if (!this->are_eabi_versions_compatible(version1, version2))
+      if (!this->are_eabi_versions_compatible(version1, version2)
+	  && parameters->options().warn_mismatch())
 	gold_error(_("Source object %s has EABI version %d but output has "
 		     "EABI version %d."),
 		   name.c_str(),
@@ -9381,7 +9423,8 @@ Target_arm<big_endian>::merge_object_attributes(
       if (out_attr[elfcpp::Tag_ABI_FP_number_model].int_value() == 0)
 	out_attr[elfcpp::Tag_ABI_VFP_args].set_int_value(
 	    in_attr[elfcpp::Tag_ABI_VFP_args].int_value());
-      else if (in_attr[elfcpp::Tag_ABI_FP_number_model].int_value() != 0)
+      else if (in_attr[elfcpp::Tag_ABI_FP_number_model].int_value() != 0
+	       && parameters->options().warn_mismatch())
         gold_error(_("%s uses VFP register arguments, output does not"),
 		   name);
     }
@@ -9525,7 +9568,7 @@ Target_arm<big_endian>::merge_object_attributes(
 			   && (out_attr[i].int_value() == 'A'
 			       || out_attr[i].int_value() == 'R')))
 		; // Do nothing.
-	      else
+	      else if (parameters->options().warn_mismatch())
 		{
 		  gold_error
 		    (_("conflicting architecture profiles %c/%c"),
@@ -9580,7 +9623,9 @@ Target_arm<big_endian>::merge_object_attributes(
 	case elfcpp::Tag_PCS_config:
 	  if (out_attr[i].int_value() == 0)
 	    out_attr[i].set_int_value(in_attr[i].int_value());
-	  else if (in_attr[i].int_value() != 0 && out_attr[i].int_value() != 0)
+	  else if (in_attr[i].int_value() != 0
+		   && out_attr[i].int_value() != 0
+		   && parameters->options().warn_mismatch())
 	    {
 	      // It's sometimes ok to mix different configs, so this is only
 	      // a warning.
@@ -9590,7 +9635,8 @@ Target_arm<big_endian>::merge_object_attributes(
 	case elfcpp::Tag_ABI_PCS_R9_use:
 	  if (in_attr[i].int_value() != out_attr[i].int_value()
 	      && out_attr[i].int_value() != elfcpp::AEABI_R9_unused
-	      && in_attr[i].int_value() != elfcpp::AEABI_R9_unused)
+	      && in_attr[i].int_value() != elfcpp::AEABI_R9_unused
+	      && parameters->options().warn_mismatch())
 	    {
 	      gold_error(_("%s: conflicting use of R9"), name);
 	    }
@@ -9602,11 +9648,12 @@ Target_arm<big_endian>::merge_object_attributes(
 	      && (in_attr[elfcpp::Tag_ABI_PCS_R9_use].int_value()
 		  != elfcpp::AEABI_R9_SB)
 	      && (out_attr[elfcpp::Tag_ABI_PCS_R9_use].int_value()
-		  != elfcpp::AEABI_R9_unused))
+		  != elfcpp::AEABI_R9_unused)
+	      && parameters->options().warn_mismatch())
 	    {
 	      gold_error(_("%s: SB relative addressing conflicts with use "
 			   "of R9"),
-			 name);
+			   name);
 	    }
 	  // Use the smallest value specified.
 	  if (in_attr[i].int_value() < out_attr[i].int_value())
@@ -9616,7 +9663,8 @@ Target_arm<big_endian>::merge_object_attributes(
 	  // FIXME: Make it possible to turn off this warning.
 	  if (out_attr[i].int_value()
 	      && in_attr[i].int_value()
-	      && out_attr[i].int_value() != in_attr[i].int_value())
+	      && out_attr[i].int_value() != in_attr[i].int_value()
+	      && parameters->options().warn_mismatch())
 	    {
 	      gold_warning(_("%s uses %u-byte wchar_t yet the output is to "
 			     "use %u-byte wchar_t; use of wchar_t values "
@@ -9639,7 +9687,8 @@ Target_arm<big_endian>::merge_object_attributes(
 		}
 	      // FIXME: Make it possible to turn off this warning.
 	      else if (in_attr[i].int_value() != elfcpp::AEABI_enum_forced_wide
-		       && out_attr[i].int_value() != in_attr[i].int_value())
+		       && out_attr[i].int_value() != in_attr[i].int_value()
+		       && parameters->options().warn_mismatch())
 		{
 		  unsigned int in_value = in_attr[i].int_value();
 		  unsigned int out_value = out_attr[i].int_value();
@@ -9656,7 +9705,8 @@ Target_arm<big_endian>::merge_object_attributes(
 	  // Aready done.
 	  break;
 	case elfcpp::Tag_ABI_WMMX_args:
-	  if (in_attr[i].int_value() != out_attr[i].int_value())
+	  if (in_attr[i].int_value() != out_attr[i].int_value()
+	      && parameters->options().warn_mismatch())
 	    {
 	      gold_error(_("%s uses iWMMXt register arguments, output does "
 			   "not"),
@@ -9677,7 +9727,8 @@ Target_arm<big_endian>::merge_object_attributes(
 	case elfcpp::Tag_ABI_FP_16bit_format:
 	  if (in_attr[i].int_value() != 0 && out_attr[i].int_value() != 0)
 	    {
-	      if (in_attr[i].int_value() != out_attr[i].int_value())
+	      if (in_attr[i].int_value() != out_attr[i].int_value()
+		  && parameters->options().warn_mismatch())
 		gold_error(_("fp16 format mismatch between %s and output"),
 			   name);
 	    }
@@ -9714,7 +9765,8 @@ Target_arm<big_endian>::merge_object_attributes(
 		     || in_attr[i].string_value() != "")
 	      err_object = name;
 
-	    if (err_object != NULL)
+	    if (err_object != NULL
+		&& parameters->options().warn_mismatch())
 	      {
 		// Attribute numbers >=64 (mod 128) can be safely ignored.
 		if ((i & 127) < 64)
@@ -9806,7 +9858,7 @@ Target_arm<big_endian>::merge_object_attributes(
 	    }
 	}
 
-      if (err_object)
+      if (err_object && parameters->options().warn_mismatch())
 	{
 	  // Attribute numbers >=64 (mod 128) can be safely ignored.  */
 	  if ((err_tag & 127) < 64)
diff --git a/gold/gold.cc b/gold/gold.cc
index aa7689ff613..b5508aef47d 100644
--- a/gold/gold.cc
+++ b/gold/gold.cc
@@ -532,13 +532,23 @@ queue_middle_tasks(const General_options& options,
         }
     }
 
-  // If we failed to open any input files, it's possible for
-  // THIS_BLOCKER to be NULL here.  There's no real point in
-  // continuing if that happens.
   if (this_blocker == NULL)
     {
-      gold_assert(parameters->errors()->error_count() > 0);
-      gold_exit(false);
+      if (input_objects->number_of_relobjs() == 0)
+	{
+	  // If we are given only archives in input, we have no regular
+	  // objects and THIS_BLOCKER is NULL here.  Create a dummy
+	  // blocker here so that we can run the layout task immediately.
+	  this_blocker = new Task_token(true);
+	}
+      else 
+	{
+	  // If we failed to open any input files, it's possible for
+	  // THIS_BLOCKER to be NULL here.  There's no real point in
+	  // continuing if that happens.
+	  gold_assert(parameters->errors()->error_count() > 0);
+	  gold_exit(false);
+	}
     }
 
   // When all those tasks are complete, we can start laying out the
diff --git a/gold/options.cc b/gold/options.cc
index 0eb38ada837..c566b99b2ad 100644
--- a/gold/options.cc
+++ b/gold/options.cc
@@ -614,6 +614,18 @@ General_options::parse_fix_v4bx_interworking(const char*, const char*,
   this->fix_v4bx_ = FIX_V4BX_INTERWORKING;
 }
 
+void
+General_options::parse_EB(const char*, const char*, Command_line*)
+{
+  this->endianness_ = ENDIANNESS_BIG;
+}
+
+void
+General_options::parse_EL(const char*, const char*, Command_line*)
+{
+  this->endianness_ = ENDIANNESS_LITTLE;
+}
+
 } // End namespace gold.
 
 namespace
@@ -845,7 +857,8 @@ General_options::General_options()
     excluded_libs_(),
     symbols_to_retain_(),
     section_starts_(),
-    fix_v4bx_(FIX_V4BX_NONE)
+    fix_v4bx_(FIX_V4BX_NONE),
+    endianness_(ENDIANNESS_NOT_SET)
 {
   // Turn off option registration once construction is complete.
   gold::options::ready_to_register = false;
diff --git a/gold/options.h b/gold/options.h
index 3a234d0ba5d..049a7eeca7c 100644
--- a/gold/options.h
+++ b/gold/options.h
@@ -713,9 +713,15 @@ class General_options
               N_("Export all dynamic symbols"),
 	      N_("Do not export all dynamic symbols (default)"));
 
+  DEFINE_special(EB, options::ONE_DASH, '\0',
+		 N_("Link big-endian objects."), NULL);
+
   DEFINE_bool(eh_frame_hdr, options::TWO_DASHES, '\0', false,
               N_("Create exception frame header"), NULL);
 
+  DEFINE_special(EL, options::ONE_DASH, '\0',
+		 N_("Link little-endian objects."), NULL);
+
   DEFINE_bool(fatal_warnings, options::TWO_DASHES, '\0', false,
 	      N_("Treat warnings as errors"),
 	      N_("Do not treat warnings as errors"));
@@ -824,12 +830,18 @@ class General_options
   DEFINE_string(oformat, options::EXACTLY_TWO_DASHES, '\0', "elf",
 		N_("Set output format"), N_("[binary]"));
 
+  DEFINE_bool(p, options::ONE_DASH, '\0', false,
+	      N_("(ARM only) Ignore for backward compatibility"), NULL);
+
   DEFINE_bool(pie, options::ONE_DASH, '\0', false,
 	      N_("Create a position independent executable"), NULL);
   DEFINE_bool_alias(pic_executable, pie, options::TWO_DASHES, '\0',
 		    N_("Create a position independent executable"), NULL,
 		    false);
 
+  DEFINE_bool(pipeline_knowledge, options::ONE_DASH, '\0', false,
+	      NULL, N_("(ARM only) Ignore for backward compatibility"));
+
 #ifdef ENABLE_PLUGINS
   DEFINE_special(plugin, options::TWO_DASHES, '\0',
                  N_("Load a plugin library"), N_("PLUGIN"));
@@ -992,6 +1004,9 @@ class General_options
   DEFINE_bool(warn_constructors, options::TWO_DASHES, '\0', false,
 	      N_("Ignored"), N_("Ignored"));
 
+  DEFINE_bool(warn_mismatch, options::TWO_DASHES, '\0', true,
+	      NULL, N_("Don't warn about mismatched input files"));
+
   DEFINE_bool(warn_multiple_gp, options::TWO_DASHES, '\0', false,
 	      N_("Ignored"), NULL);
 
@@ -1256,6 +1271,17 @@ class General_options
   fix_v4bx() const
   { return (this->fix_v4bx_); }
 
+  enum Endianness
+  {
+    ENDIANNESS_NOT_SET,
+    ENDIANNESS_BIG,
+    ENDIANNESS_LITTLE
+  };
+
+  Endianness
+  endianness() const
+  { return this->endianness_; }
+
  private:
   // Don't copy this structure.
   General_options(const General_options&);
@@ -1347,6 +1373,8 @@ class General_options
   std::map<std::string, uint64_t> section_starts_;
   // Whether to process armv4 bx instruction relocation.
   Fix_v4bx fix_v4bx_;
+  // Endianness.
+  Endianness endianness_;
 };
 
 // The position-dependent options.  We use this to store the state of
diff --git a/gold/parameters.cc b/gold/parameters.cc
index 1d0f082e197..4430388a674 100644
--- a/gold/parameters.cc
+++ b/gold/parameters.cc
@@ -89,6 +89,8 @@ Parameters::set_options(const General_options* options)
   // If --verbose is set, it acts as "--debug=files".
   if (options->verbose())
     this->debug_ |= DEBUG_FILES;
+  if (this->target_valid())
+    this->check_target_endianness();
 }
 
 void
@@ -113,6 +115,8 @@ Parameters::set_target_once(Target* target)
 {
   gold_assert(this->target_ == NULL);
   this->target_ = target;
+  if (this->options_valid())
+    this->check_target_endianness();
 }
 
 // Clear the target, for testing.
@@ -181,6 +185,29 @@ Parameters::size_and_endianness() const
     gold_unreachable();
 }
 
+// If output endianness is specified in command line, check that it does
+// not conflict with the target.
+
+void
+Parameters::check_target_endianness()
+{
+  General_options::Endianness endianness = this->options().endianness();
+  if (endianness != General_options::ENDIANNESS_NOT_SET)
+    {
+      bool big_endian;
+      if (endianness == General_options::ENDIANNESS_BIG)
+	big_endian = true;
+      else
+	{
+	  gold_assert(endianness == General_options::ENDIANNESS_LITTLE);
+	  big_endian = false;;
+	}
+      
+      if (this->target().is_big_endian() != big_endian)
+	gold_error(_("input file does not match -EB/EL option"));
+    }
+}
+
 void
 set_parameters_errors(Errors* errors)
 { static_parameters.set_errors(errors); }
@@ -227,9 +254,18 @@ parameters_force_valid_target()
     }
 
   // The GOLD_DEFAULT_xx macros are defined by the configure script.
+  bool is_big_endian;
+  General_options::Endianness endianness = parameters->options().endianness();
+  if (endianness == General_options::ENDIANNESS_BIG)
+    is_big_endian = true;
+  else if (endianness == General_options::ENDIANNESS_LITTLE)
+    is_big_endian = false;
+  else
+    is_big_endian = GOLD_DEFAULT_BIG_ENDIAN;
+
   Target* target = select_target(elfcpp::GOLD_DEFAULT_MACHINE,
 				 GOLD_DEFAULT_SIZE,
-				 GOLD_DEFAULT_BIG_ENDIAN,
+				 is_big_endian,
 				 elfcpp::GOLD_DEFAULT_OSABI,
 				 0);
   gold_assert(target != NULL);
diff --git a/gold/parameters.h b/gold/parameters.h
index 85b8ef6d67d..0ca2941e0ab 100644
--- a/gold/parameters.h
+++ b/gold/parameters.h
@@ -149,6 +149,9 @@ class Parameters
   void
   set_target_once(Target*);
 
+  void
+  check_target_endianness();
+
   friend class Set_parameters_target_once;
 
   Errors* errors_;
diff --git a/gold/target.h b/gold/target.h
index 007b16d0dec..f2fdcc9cbbd 100644
--- a/gold/target.h
+++ b/gold/target.h
@@ -461,7 +461,7 @@ class Target
 		     std::string*, std::string*) const;
 
   // make_elf_object hooks.  There are four versions of these for
-  // different address sizes and endianities.
+  // different address sizes and endianness.
 
   // Set processor specific flags.
   void
@@ -544,7 +544,7 @@ class Target
 
  private:
   // The implementations of the four do_make_elf_object virtual functions are
-  // almost identical except for their sizes and endianity.  We use a template.
+  // almost identical except for their sizes and endianness.  We use a template.
   // for their implementations.
   template<int size, bool big_endian>
   inline Object*