[GOLD][PATCH] Set ARM ABI information in ELF file header.

Doug Kwan (關振德) dougkwan@google.com
Tue Oct 27 01:32:00 GMT 2009


Hi,

    This patch adds code to set proper flags in the processor-specific
flags in the ELF file header.  Previously we always set e_flags to 0
on all target.  This patch add methods processor_specific_flags and
set_processor_specific_flags in Target so that Output_file_header can
get the flags.   For targets that merge processor-specific flags from
input objects,  we also track whether the flags have been set at least
once.  Currently only the ARM target sets the flags correctly.

2009-10-26  Doug Kwan  <dougkwan@google.com>

elfcpp/ChangeLog:

        * arm.h (EF_ARM_RELEXEC, EF_ARM_HASENTRY, EF_ARM_INTERWORK,
        EF_ARM_APCS_26, EF_ARM_APCS_FLOAT, EF_ARM_PIC, EF_ARM_ALIGN8,
        EF_ARM_NEW_ABI, EF_ARM_OLD_ABI, EF_ARM_SOFT_FLOAT, EF_ARM_VFP_FLOAT,
        EF_ARM_MAVERICK_FLOAT, EF_ARM_EABIMASK, EF_ARM_BE8, EF_ARM_LE8,
        EF_ARM_EABI_UNKNOWN, EF_ARM_EABI_VER1, EF_ARM_EABI_VER2,
        EF_ARM_EABI_VER3, EF_ARM_EABI_VER4, EF_ARM_EABI_VER5): New enums
        for processor-specific flags in ELF file header.
        (arm_eabi_version): New inline function.

gold/ChangeLog:

        * arm.cc (Target_arm::do_adjust_elf_header): New method declaration.
        (Target_arm::are_eabi_versions_compatible): Same.
        (Target_arm::do_make_elf_object): New overloaded method declaration
        and definitions.
        (Target_arm::are_eabi_versions_compatible,
        Target_arm::merge_processor_specific_flags,
        Target_arm::do_adjust_elf_header, Target_arm::do_make_elf_object):
        New method definitions.
        * output.cc (Output_file_header::do_sized_write): Set e_flags using
        values from target.
        * target.h (Target::processor_specific_flags,
        Target::are_processor_specific_flags_set): New method definitions.
        (Target::Target): Initialize processor_specific_flags_ and
        are_processor_specific_flags_set_.
        (set_processor_specific_flags): New method definition.
        (processor_specific_flags_, are_processor_specific_flags_set_):
        New data member declarations.

-Doug
-------------- next part --------------
Index: elfcpp/arm.h
===================================================================
RCS file: /cvs/src/src/elfcpp/arm.h,v
retrieving revision 1.1
diff -u -p -r1.1 arm.h
--- elfcpp/arm.h	27 May 2009 18:27:42 -0000	1.1
+++ elfcpp/arm.h	27 Oct 2009 01:19:01 -0000
@@ -199,6 +199,43 @@ enum
   // 160 - 255			Unallocated
 };
 
+// e_flags values used for ARM.
+
+enum
+{
+  EF_ARM_RELEXEC = 0x01,
+  EF_ARM_HASENTRY = 0x02,
+  EF_ARM_INTERWORK = 0x04,
+  EF_ARM_APCS_26 = 0x08,
+  EF_ARM_APCS_FLOAT = 0x10,
+  EF_ARM_PIC = 0x20,
+  EF_ARM_ALIGN8 = 0x40,		// 8-bit structure alignment is in use.
+  EF_ARM_NEW_ABI = 0x80,
+  EF_ARM_OLD_ABI = 0x100,
+  EF_ARM_SOFT_FLOAT = 0x200,
+  EF_ARM_VFP_FLOAT = 0x400,
+  EF_ARM_MAVERICK_FLOAT = 0x800,
+
+  EF_ARM_EABIMASK = 0xFF000000,
+
+  // Constants defined in AAELF.
+  EF_ARM_BE8 = 0x00800000,
+  EF_ARM_LE8 = 0x00400000,
+
+  EF_ARM_EABI_UNKNOWN = 0x00000000,
+  EF_ARM_EABI_VER1 = 0x01000000,
+  EF_ARM_EABI_VER2 = 0x02000000,
+  EF_ARM_EABI_VER3 = 0x03000000,
+  EF_ARM_EABI_VER4 = 0x04000000,
+  EF_ARM_EABI_VER5 = 0x05000000,
+};
+
+// Extract EABI version from flags.
+
+inline Elf_Word
+arm_eabi_version(Elf_Word flags)
+{ return flags & EF_ARM_EABIMASK; }
+
 } // End namespace elfcpp.
 
 #endif // !defined(ELFCPP_ARM_H)
Index: gold/arm.cc
===================================================================
RCS file: /cvs/src/src/gold/arm.cc,v
retrieving revision 1.20
diff -u -p -r1.20 arm.cc
--- gold/arm.cc	24 Oct 2009 09:36:15 -0000	1.20
+++ gold/arm.cc	27 Oct 2009 01:19:03 -0000
@@ -1103,6 +1103,10 @@ class Target_arm : public Sized_target<3
     return static_cast<const Target_arm<big_endian>&>(parameters->target());
   }
 
+ protected:
+  void
+  do_adjust_elf_header(unsigned char* view, int len) const;
+
  private:
   // The class which scans relocations.
   class Scan
@@ -1275,6 +1279,34 @@ class Target_arm : public Sized_target<3
 				  this->rel_dyn_section(layout));
   }
 
+  // Whether two EABI versions are compatible.
+  static bool
+  are_eabi_versions_compatible(elfcpp::Elf_Word v1, elfcpp::Elf_Word v2);
+
+  // Merge processor-specific flags from input object and those in the ELF
+  // header of the output.
+  void
+  merge_processor_specific_flags(const std::string&, elfcpp::Elf_Word);
+
+  Object*
+  do_make_elf_object(const std::string&, Input_file*, off_t,
+		     const elfcpp::Ehdr<32, big_endian>& ehdr);
+
+  Object*
+  do_make_elf_object(const std::string&, Input_file*, off_t,
+		     const elfcpp::Ehdr<32, !big_endian>&)
+  { gold_unreachable(); }
+
+  Object*
+  do_make_elf_object(const std::string&, Input_file*, off_t,
+		      const elfcpp::Ehdr<64, false>&)
+  { gold_unreachable(); }
+
+  Object*
+  do_make_elf_object(const std::string&, Input_file*, off_t,
+		     const elfcpp::Ehdr<64, true>&)
+  { gold_unreachable(); }
+
   // Information about this specific target which we pass to the
   // general Target structure.
   static const Target::Target_info arm_info;
@@ -4254,6 +4286,235 @@ Target_arm<big_endian>::get_real_reloc_t
     }
 }
 
+// Whether if two EABI versions V1 and V2 are compatible.
+
+template<bool big_endian>
+bool
+Target_arm<big_endian>::are_eabi_versions_compatible(
+    elfcpp::Elf_Word v1,
+    elfcpp::Elf_Word v2)
+{
+  // v4 and v5 are the same spec before and after it was released,
+  // so allow mixing them.
+  if ((v1 == elfcpp::EF_ARM_EABI_VER4 && v2 == elfcpp::EF_ARM_EABI_VER5)
+      || (v1 == elfcpp::EF_ARM_EABI_VER5 && v2 == elfcpp::EF_ARM_EABI_VER4))
+    return true;
+
+  return v1 == v2;
+}
+
+// Combine FLAGS from an input object called NAME and the processor-specific
+// flags in the ELF header of the output.  Much of this is adapted from the
+// processor-specific flags merging code in elf32_arm_merge_private_bfd_data
+// in bfd/elf32-arm.c.
+
+template<bool big_endian>
+void
+Target_arm<big_endian>::merge_processor_specific_flags(
+    const std::string& name,
+    elfcpp::Elf_Word flags)
+{
+  if (this->are_processor_specific_flags_set())
+    {
+      elfcpp::Elf_Word out_flags = this->processor_specific_flags();
+
+      // Nothing to merge if flags equal to those in output.
+      if (flags == out_flags)
+	return;
+
+      // Complain about various flag mismatches.
+      const char* name_as_c_string = name.c_str();
+      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))
+	{
+	  gold_error(_("Source object %s has EABI version %d but output has "
+		       "EABI version %d."),
+		     name_as_c_string,
+		     (flags & elfcpp::EF_ARM_EABIMASK) >> 24,
+		     (out_flags & elfcpp::EF_ARM_EABIMASK) >> 24);
+	}
+
+      // Not sure what needs to be checked for EABI versions >= 1.
+      // FIXME: VxWorks libraries do not use these flags but we do not
+      // support VxWorks yet.
+      elfcpp::Elf_Word difference = flags ^ out_flags;
+      if (elfcpp::arm_eabi_version(flags) == elfcpp::EF_ARM_EABI_UNKNOWN)
+	{
+	  if ((difference & elfcpp::EF_ARM_APCS_26) != 0)
+	    {
+	      gold_error(_("%s is compiled for APCS-%d, whereas output uses "
+			   "APCS-%d."),
+			 name_as_c_string,
+			 (flags & elfcpp::EF_ARM_APCS_26) ? 26 : 32,
+			 (out_flags & elfcpp::EF_ARM_APCS_26) ? 26 : 32);
+	    }
+
+	  if ((difference & elfcpp::EF_ARM_APCS_FLOAT) != 0)
+	    {
+	      if ((flags & elfcpp::EF_ARM_APCS_FLOAT) != 0)
+		gold_error(_("%s passes floats in float registers, whereas "
+			     "output passes them in integer registers."),
+			   name_as_c_string);
+	      else
+		gold_error(_("%s passes floats in integer registers, whereas "
+			     "output passes them in float registers."),
+			   name_as_c_string);
+	    }
+
+	  if ((difference & elfcpp::EF_ARM_VFP_FLOAT) != 0)
+	    {
+	      if ((flags & elfcpp::EF_ARM_VFP_FLOAT) != 0)
+		gold_error(_("%s uses VFP instructions, whereas output does "
+			     "not."),
+			   name_as_c_string);
+	      else
+		gold_error(_("%s uses FPA instructions, whereas output does "
+			     "not."),
+			   name_as_c_string);
+	    }
+
+	  if ((difference & elfcpp::EF_ARM_MAVERICK_FLOAT) != 0)
+	    {
+	      if ((flags & elfcpp::EF_ARM_MAVERICK_FLOAT) != 0)
+		gold_error(_("%s uses Maverick instructions, whereas output "
+			     "does not."),
+			   name_as_c_string);
+	      else
+		gold_error(_("%s does not use Maverick instructions, whereas "
+			     "output does."),
+			   name_as_c_string);
+	    }
+
+	  if ((difference & elfcpp::EF_ARM_SOFT_FLOAT) != 0)
+	    {
+	      // We can allow interworking between code that is VFP format
+	      // layout, and uses either soft float or integer regs for
+	      // passing floating point arguments and results.  We already
+	      // know that the APCS_FLOAT flags match; similarly for VFP
+	      // flags.
+	      if ((flags & elfcpp::EF_ARM_APCS_FLOAT) != 0
+		  || (flags & elfcpp::EF_ARM_VFP_FLOAT) == 0)
+		{
+		  if ((flags & elfcpp::EF_ARM_SOFT_FLOAT) != 0)
+		    gold_error(_("%s uses software FP, whereas output uses "
+				 "hardware FP."),
+			       name_as_c_string);
+		  else
+		    gold_error(_("%s uses hardware FP, whereas output uses "
+				 "software FP."),
+			       name_as_c_string);
+		}
+	    }
+
+	  // Interworking mismatch is only a warning.
+	  if ((difference & elfcpp::EF_ARM_INTERWORK) != 0)
+	    {
+	      if ((flags & elfcpp::EF_ARM_INTERWORK) != 0)
+		gold_warning(_("%s supports interworking, whereas output "
+			       "does not."),
+			     name_as_c_string);
+	      else
+		gold_warning(_("%s does not support interworking, whereas "
+			       "output does."),
+			     name_as_c_string);
+		
+		// Clear interworking flag in output.
+		out_flags &= ~elfcpp::EF_ARM_INTERWORK;
+	    }
+
+	  // Merge PIC flags.
+	  if ((difference & elfcpp::EF_ARM_PIC) != 0)
+	    {
+	      // Clear PIC flag in output silently if there is a conflict.
+	      out_flags &= ~elfcpp::EF_ARM_PIC;
+	    }
+
+	}
+
+      // Update processor-specific flags in output if necessary.
+      // This happens when we clear a flag due to conflict.
+      if (out_flags != this->processor_specific_flags())
+	this->set_processor_specific_flags(out_flags);
+    }
+  else
+    {
+      // This is the first time, just copy the flags.
+      this->set_processor_specific_flags(flags);
+    }
+}
+
+// Adjust ELF file header.
+template<bool big_endian>
+void
+Target_arm<big_endian>::do_adjust_elf_header(
+    unsigned char* view,
+    int len) const
+{
+  gold_assert(len == elfcpp::Elf_sizes<32>::ehdr_size);
+
+  elfcpp::Ehdr<32, big_endian> ehdr(view);
+  unsigned char e_ident[elfcpp::EI_NIDENT];
+  memcpy(e_ident, ehdr.get_e_ident(), elfcpp::EI_NIDENT);
+
+  if (elfcpp::arm_eabi_version(this->processor_specific_flags())
+      == elfcpp::EF_ARM_EABI_UNKNOWN)
+    e_ident[elfcpp::EI_OSABI] = elfcpp::ELFOSABI_ARM;
+  else
+    e_ident[elfcpp::EI_OSABI] = 0;
+  e_ident[elfcpp::EI_ABIVERSION] = 0;
+
+  // Adjust processor-specific flags.
+  elfcpp::Elf_Word e_flags = ehdr.get_e_flags();
+  
+  // Set EF_ARM_HASENTRY if it is not a shared object.
+  if (!parameters->options().shared())
+    e_flags |= elfcpp::EF_ARM_HASENTRY;
+  else
+    e_flags &= ~elfcpp::EF_ARM_HASENTRY;
+
+  // FIXME: Do EF_ARM_BE8 adjustment.
+
+  elfcpp::Ehdr_write<32, big_endian> oehdr(view);
+  oehdr.put_e_ident(e_ident);
+  oehdr.put_e_flags(e_flags);
+}
+
+// Make an ELF object.
+
+template<bool big_endian>
+Object*
+Target_arm<big_endian>::do_make_elf_object(
+    const std::string& name,
+    Input_file* input_file,
+    off_t offset, const elfcpp::Ehdr<32, big_endian>& ehdr)
+{
+  // Merge processor specific flags from object to those of the output.
+  this->merge_processor_specific_flags(name, ehdr.get_e_flags());
+
+  int et = ehdr.get_e_type();
+  if (et == elfcpp::ET_REL)
+    {
+      Sized_relobj<32, big_endian>* obj =
+        new Sized_relobj<32, big_endian>(name, input_file, offset, ehdr);
+      obj->setup();
+      return obj;
+    }
+  else if (et == elfcpp::ET_DYN)
+    {
+      Sized_dynobj<32, big_endian>* obj =
+        new Sized_dynobj<32, big_endian>(name, input_file, offset, ehdr);
+      obj->setup();
+      return obj;
+    }
+  else
+    {
+      gold_error(_("%s: unsupported ELF file type %d"),
+                 name.c_str(), et);
+      return NULL;
+    }
+}
+
 // The selector for arm object files.
 
 template<bool big_endian>
Index: gold/output.cc
===================================================================
RCS file: /cvs/src/src/gold/output.cc,v
retrieving revision 1.101
diff -u -p -r1.101 output.cc
--- gold/output.cc	16 Oct 2009 18:34:53 -0000	1.101
+++ gold/output.cc	27 Oct 2009 01:19:03 -0000
@@ -459,10 +459,7 @@ Output_file_header::do_sized_write(Outpu
     oehdr.put_e_phoff(this->segment_header_->offset());
 
   oehdr.put_e_shoff(this->section_header_->offset());
-
-  // FIXME: The target needs to set the flags.
-  oehdr.put_e_flags(0);
-
+  oehdr.put_e_flags(this->target_->processor_specific_flags());
   oehdr.put_e_ehsize(elfcpp::Elf_sizes<size>::ehdr_size);
 
   if (this->segment_header_ == NULL)
Index: gold/target.h
===================================================================
RCS file: /cvs/src/src/gold/target.h,v
retrieving revision 1.38
diff -u -p -r1.38 target.h
--- gold/target.h	9 Oct 2009 23:18:19 -0000	1.38
+++ gold/target.h	27 Oct 2009 01:19:03 -0000
@@ -80,6 +80,16 @@ class Target
   machine_code() const
   { return this->pti_->machine_code; }
 
+  // Processor specific flags to store in e_flags field of ELF header.
+  elfcpp::Elf_Word
+  processor_specific_flags() const
+  { return this->processor_specific_flags_; }
+
+  // Whether processor specific flags are set at least once.
+  bool
+  are_processor_specific_flags_set() const
+  { return this->are_processor_specific_flags_set_; }
+
   // Whether this target has a specific make_symbol function.
   bool
   has_make_symbol() const
@@ -315,7 +325,8 @@ class Target
   };
 
   Target(const Target_info* pti)
-    : pti_(pti)
+    : pti_(pti), processor_specific_flags_(0),
+      are_processor_specific_flags_set_(false)
   { }
 
   // Virtual function which may be implemented by the child class.
@@ -365,6 +376,14 @@ class Target
   // make_elf_object hooks.  There are four versions of these for
   // different address sizes and endianities.
 
+  // Set processor specific flags.
+  void
+  set_processor_specific_flags(elfcpp::Elf_Word flags)
+  {
+    this->processor_specific_flags_ = flags;
+    this->are_processor_specific_flags_set_ = true;
+  }
+  
 #ifdef HAVE_TARGET_32_LITTLE
   // Virtual functions which may be overriden by the child class.
   virtual Object*
@@ -434,6 +453,10 @@ class Target
 
   // The target information.
   const Target_info* pti_;
+  // Processor-specific flags.
+  elfcpp::Elf_Word processor_specific_flags_;
+  // Whether the processor-specific flags are set at least once.
+  bool are_processor_specific_flags_set_;
 };
 
 // The abstract class for a specific size and endianness of target.


More information about the Binutils mailing list