This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[GOLD] powerpc64 ODR violation check


This is a first pass at fixing detect_odr_violations for PowerPC64.
PowerPC64 uses function descriptors, with the address of a function
defined to be that of its descriptor in the .opd section.  This causes
difficulty with detect_odr_violations which wants to match up function
symbols with their Dwarf line number info.  Since the function symbol
isn't defined on function code, no lines match.

So what I need to do for powerpc64 is translate a function symbol
location in .opd to the corresponding location in the function text
section.   ie. I need to do an OPD lookup.  However, the opd_ent_
vector is only set up for relocatable objects after reading
relocations.  That means detect_odr_violations must be run later, or I
need to read .opd relocs early.  The latter option is rather more
difficult, and the former seems to work on both powerpc and x86_64,
so that's what I did.  Does anyone see a problem with this?

I have yet to implement read_dyn_opd(), and may decide to invoke that
function around the same time symbols are read from dynamic objects,
when section headers are likely to be hot in cache.

	* gold.cc (queue_middle_tasks): Move detect_odr_violations..
	* layout.cc (Layout_task_runner::run): ..to here.
	* symtab.h (struct Symbol_location): Extract from..
	(class Symbol_table): ..here.
	* symtab.cc (Symbol_table::linenos_from_loc): Invoke func_desc_lookup.
	* target.h (class Target): Add has_func_descriptors,
	func_desc_lookup and do_func_desc_lookup functions.
	(class Sized_target): Add do_func_desc_lookup function.
	(Target::Target_info): Add has_func_descriptors bool.
	* powerpc.cc (class Powerpc_dynobj): New.
	(Target_powerpc::do_func_desc_loopkup): New function.
	(powerpc_info): Update.
	(Powerpc_dynobj::read_dyn_opd): New stub.
	(Target_powerpc::do_make_elf_object): Make a Powerpc_dynobj.
	* arm.cc, * i386.cc, * sparc.cc, * tilegx.cc, * x86_64.cc,
	* testsuite/testfile.cc: Update Target_info initialization.

Index: gold/gold.cc
===================================================================
RCS file: /cvs/src/src/gold/gold.cc,v
retrieving revision 1.103
diff -u -p -r1.103 gold.cc
--- gold/gold.cc	17 Oct 2012 11:58:39 -0000	1.103
+++ gold/gold.cc	6 Mar 2013 09:51:11 -0000
@@ -653,10 +653,6 @@ queue_middle_tasks(const General_options
   // dynamic objects that it depends upon.
   input_objects->check_dynamic_dependencies();
 
-  // See if any of the input definitions violate the One Definition Rule.
-  // TODO: if this is too slow, do this as a task, rather than inline.
-  symtab->detect_odr_violations(task, options.output_file_name());
-
   // Do the --no-undefined-version check.
   if (!parameters->options().undefined_version())
     {
Index: gold/layout.cc
===================================================================
RCS file: /cvs/src/src/gold/layout.cc,v
retrieving revision 1.245
diff -u -p -r1.245 layout.cc
--- gold/layout.cc	24 Jan 2013 18:49:54 -0000	1.245
+++ gold/layout.cc	6 Mar 2013 09:51:11 -0000
@@ -317,6 +317,10 @@ Layout::Relaxation_debug_check::verify_s
 void
 Layout_task_runner::run(Workqueue* workqueue, const Task* task)
 {
+  // See if any of the input definitions violate the One Definition Rule.
+  // TODO: if this is too slow, do this as a task, rather than inline.
+  this->symtab_->detect_odr_violations(task, this->options_.output_file_name());
+
   Layout* layout = this->layout_;
   off_t file_size = layout->finalize(this->input_objects_,
 				     this->symtab_,
Index: gold/symtab.h
===================================================================
RCS file: /cvs/src/src/gold/symtab.h,v
retrieving revision 1.128
diff -u -p -r1.128 symtab.h
--- gold/symtab.h	18 Aug 2012 11:12:50 -0000	1.128
+++ gold/symtab.h	6 Mar 2013 09:51:12 -0000
@@ -1180,6 +1180,19 @@ struct Define_symbol_in_segment
   bool only_if_ref;
 };
 
+struct Symbol_location
+{
+  Object* object;         // Object where the symbol is defined.
+  unsigned int shndx;     // Section-in-object where the symbol is defined.
+  off_t offset;           // Offset-in-section where the symbol is defined.
+  bool operator==(const Symbol_location& that) const
+  {
+    return (this->object == that.object
+	    && this->shndx == that.shndx
+	    && this->offset == that.offset);
+  }
+};
+
 // This class manages warnings.  Warnings are a GNU extension.  When
 // we see a section named .gnu.warning.SYM in an object file, and if
 // we wind using the definition of SYM from that object file, then we
@@ -1599,19 +1612,6 @@ class Symbol_table
   // the locations the symbols is (weakly) defined (and certain other
   // conditions are met).  This map will be used later to detect
   // possible One Definition Rule (ODR) violations.
-  struct Symbol_location
-  {
-    Object* object;         // Object where the symbol is defined.
-    unsigned int shndx;     // Section-in-object where the symbol is defined.
-    off_t offset;           // Offset-in-section where the symbol is defined.
-    bool operator==(const Symbol_location& that) const
-    {
-      return (this->object == that.object
-              && this->shndx == that.shndx
-              && this->offset == that.offset);
-    }
-  };
-
   struct Symbol_location_hash
   {
     size_t operator()(const Symbol_location& loc) const
Index: gold/symtab.cc
===================================================================
RCS file: /cvs/src/src/gold/symtab.cc,v
retrieving revision 1.168
diff -u -p -r1.168 symtab.cc
--- gold/symtab.cc	9 Sep 2012 03:43:51 -0000	1.168
+++ gold/symtab.cc	6 Mar 2013 09:51:12 -0000
@@ -3175,9 +3175,16 @@ Symbol_table::linenos_from_loc(const Tas
   Task_lock_obj<Object> tl(task, loc.object);
 
   std::vector<std::string> result;
+  const Symbol_location* code_loc = NULL;
+  if (parameters->target().has_func_descriptors())
+    code_loc = parameters->target().func_desc_lookup(&loc);
+  if (code_loc == NULL)
+    code_loc = &loc;
   // 16 is the size of the object-cache that one_addr2line should use.
   std::string canonical_result = Dwarf_line_info::one_addr2line(
-      loc.object, loc.shndx, loc.offset, 16, &result);
+      code_loc->object, code_loc->shndx, code_loc->offset, 16, &result);
+  if (code_loc != &loc)
+    delete code_loc;
   if (!canonical_result.empty())
     result.push_back(canonical_result);
   return result;
Index: gold/target.h
===================================================================
RCS file: /cvs/src/src/gold/target.h,v
retrieving revision 1.73
diff -u -p -r1.73 target.h
--- gold/target.h	27 Feb 2013 23:11:56 -0000	1.73
+++ gold/target.h	6 Mar 2013 09:51:12 -0000
@@ -61,6 +61,7 @@ class Output_data_got_base;
 class Output_section;
 class Input_objects;
 class Task;
+struct Symbol_location;
 
 // The abstract class for target specific handling.
 
@@ -286,6 +287,14 @@ class Target
   tls_offset_for_global(Symbol* gsym, unsigned int got_indx) const
   { return do_tls_offset_for_global(gsym, got_indx); }
 
+  bool
+  has_func_descriptors() const
+  { return this->pti_->has_func_descriptors; }
+
+  Symbol_location*
+  func_desc_lookup(const Symbol_location* loc) const
+  { return do_func_desc_lookup(loc); }
+
   // Return whether this target can use relocation types to determine
   // if a function's address is taken.
   bool
@@ -460,6 +469,8 @@ class Target
     bool has_resolve;
     // Whether this target has a specific code fill function.
     bool has_code_fill;
+    // Whether this target has function descriptors.
+    bool has_func_descriptors;
     // Whether an object file with no .note.GNU-stack sections implies
     // that the stack should be executable.
     bool is_default_stack_executable;
@@ -575,6 +586,9 @@ class Target
   do_tls_offset_for_global(Symbol*, unsigned int) const
   { gold_unreachable(); }
 
+  virtual Symbol_location*
+  do_func_desc_lookup(const Symbol_location*) const = 0;
+
   // Virtual function which may be overriden by the child class.
   virtual bool
   do_can_check_for_function_pointers() const
@@ -1009,6 +1023,10 @@ class Sized_target : public Target
 		      Object*, unsigned int,
 		      typename elfcpp::Elf_types<size>::Elf_Addr) const
   { }
+
+  virtual Symbol_location*
+  do_func_desc_lookup(const Symbol_location*) const
+  { return NULL; }
 };
 
 } // End namespace gold.
Index: gold/powerpc.cc
===================================================================
RCS file: /cvs/src/src/gold/powerpc.cc,v
retrieving revision 1.85
diff -u -p -r1.85 powerpc.cc
--- gold/powerpc.cc	6 Mar 2013 12:28:47 -0000	1.85
+++ gold/powerpc.cc	6 Mar 2013 12:41:14 -0000
@@ -320,6 +320,89 @@ private:
 };
 
 template<int size, bool big_endian>
+class Powerpc_dynobj : public Sized_dynobj<size, big_endian>
+{
+public:
+  typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
+  typedef Unordered_set<Section_id, Section_id_hash> Section_refs;
+  typedef Unordered_map<Address, Section_refs> Access_from;
+
+  Powerpc_dynobj(const std::string& name, Input_file* input_file, off_t offset,
+		 const typename elfcpp::Ehdr<size, big_endian>& ehdr)
+    : Sized_dynobj<size, big_endian>(name, input_file, offset, ehdr),
+      opd_shndx_(0), opd_ent_()
+  { }
+
+  ~Powerpc_dynobj()
+  { }
+
+  // The .opd section shndx.
+  unsigned int
+  opd_shndx() const
+  {
+    return this->opd_shndx_;
+  }
+
+  // Init OPD entry arrays.
+  void
+  init_opd(size_t opd_size)
+  {
+    size_t count = this->opd_ent_ndx(opd_size);
+    this->opd_ent_.resize(count);
+  }
+
+  // Return section and offset of function entry for .opd + R_OFF.
+  unsigned int
+  get_opd_ent(Address r_off, Address* value = NULL) const
+  {
+    size_t ndx = this->opd_ent_ndx(r_off);
+    gold_assert(ndx < this->opd_ent_.size());
+    gold_assert(this->opd_ent_[ndx].shndx != 0);
+    if (value != NULL)
+      *value = this->opd_ent_[ndx].off;
+    return this->opd_ent_[ndx].shndx;
+  }
+
+  // Set section and offset of function entry for .opd + R_OFF.
+  void
+  set_opd_ent(Address r_off, unsigned int shndx, Address value)
+  {
+    size_t ndx = this->opd_ent_ndx(r_off);
+    gold_assert(ndx < this->opd_ent_.size());
+    this->opd_ent_[ndx].shndx = shndx;
+    this->opd_ent_[ndx].off = value;
+  }
+
+  bool
+  opd_valid() const
+  { return this->opd_shndx_ != 0; }
+
+  // Read .opd from a dynamic object, filling in opd_ent_ vector.
+  void
+  read_dyn_opd();
+
+private:
+  struct Opd_ent
+  {
+    unsigned int shndx;
+    Address off;
+  };
+
+  // Return index into opd_ent_ array for .opd entry at OFF.
+  size_t
+  opd_ent_ndx(size_t off) const
+  { return off >> 4;}
+
+  // For 64-bit the .opd section shndx.
+  unsigned int opd_shndx_;
+
+  // The first 8-byte word of an OPD entry gives the address of the
+  // entry point of the function.  Records the section and offset
+  // corresponding to the address.
+  std::vector<Opd_ent> opd_ent_;
+};
+
+template<int size, bool big_endian>
 class Target_powerpc : public Sized_target<size, big_endian>
 {
  public:
@@ -448,6 +531,9 @@ class Target_powerpc : public Sized_targ
   int64_t
   do_tls_offset_for_global(Symbol* gsym, unsigned int got_indx) const;
 
+  Symbol_location*
+  do_func_desc_lookup(const Symbol_location*) const;
+
   // Relocate a section.
   void
   relocate_section(const Relocate_info<size, big_endian>*,
@@ -1052,6 +1138,7 @@ Target::Target_info Target_powerpc<32, t
   false,		// has_make_symbol
   false,		// has_resolve
   false,		// has_code_fill
+  false,		// has_func_descriptors
   true,			// is_default_stack_executable
   false,		// can_icf_inline_merge_sections
   '\0',			// wrap_char
@@ -1078,6 +1165,7 @@ Target::Target_info Target_powerpc<32, f
   false,		// has_make_symbol
   false,		// has_resolve
   false,		// has_code_fill
+  false,		// has_func_descriptors
   true,			// is_default_stack_executable
   false,		// can_icf_inline_merge_sections
   '\0',			// wrap_char
@@ -1104,6 +1192,7 @@ Target::Target_info Target_powerpc<64, t
   false,		// has_make_symbol
   false,		// has_resolve
   false,		// has_code_fill
+  true,			// has_func_descriptors
   true,			// is_default_stack_executable
   false,		// can_icf_inline_merge_sections
   '\0',			// wrap_char
@@ -1130,6 +1219,7 @@ Target::Target_info Target_powerpc<64, f
   false,		// has_make_symbol
   false,		// has_resolve
   false,		// has_code_fill
+  true,			// has_func_descriptors
   true,			// is_default_stack_executable
   false,		// can_icf_inline_merge_sections
   '\0',			// wrap_char
@@ -1634,6 +1724,19 @@ Powerpc_relobj<size, big_endian>::do_rea
     }
 }
 
+// Read .opd from a dynamic object, filling in opd_ent_ vector.
+
+template<int size, bool big_endian>
+void
+Powerpc_dynobj<size, big_endian>::read_dyn_opd()
+{
+  if (size == 64)
+    {
+      // Failed.  Set opd_shndx_ non-zero so we don't try again.
+      this->opd_shndx_ = (unsigned) -1;
+    }
+}
+
 // Set up some symbols.
 
 template<int size, bool big_endian>
@@ -1706,8 +1809,8 @@ Target_powerpc<size, big_endian>::do_mak
     }
   else if (et == elfcpp::ET_DYN)
     {
-      Sized_dynobj<size, big_endian>* obj =
-	new Sized_dynobj<size, big_endian>(name, input_file, offset, ehdr);
+      Powerpc_dynobj<size, big_endian>* obj =
+	new Powerpc_dynobj<size, big_endian>(name, input_file, offset, ehdr);
       obj->setup();
       return obj;
     }
@@ -5581,6 +5684,51 @@ Target_powerpc<size, big_endian>::do_gc_
     }
 }
 
+// For a symbol location in .opd, return the location of the function
+// entry.  Return NULL for other symbols.
+
+template<int size, bool big_endian>
+Symbol_location*
+Target_powerpc<size, big_endian>::do_func_desc_lookup(
+    const Symbol_location* loc) const
+{
+  if (size == 64)
+    {
+      if (loc->object->is_dynamic())
+	{
+	  Powerpc_dynobj<size, big_endian>* ppc_object
+	    = static_cast<Powerpc_dynobj<size, big_endian>*>(loc->object);
+	  if (!ppc_object->opd_valid())
+	    ppc_object->read_dyn_opd();
+	  if (loc->shndx == ppc_object->opd_shndx())
+	    {
+	      Symbol_location* code_loc = new Symbol_location;
+	      Address dest_off;
+	      code_loc->object = loc->object;
+	      code_loc->shndx = ppc_object->get_opd_ent(loc->offset, &dest_off);
+	      code_loc->offset = dest_off;
+	      return code_loc;
+	    }
+	}
+      else
+	{
+	  const Powerpc_relobj<size, big_endian>* ppc_object
+	    = static_cast<const Powerpc_relobj<size, big_endian>*>(loc->object);
+	  if (loc->shndx == ppc_object->opd_shndx())
+	    {
+	      Symbol_location* code_loc = new Symbol_location;
+	      Address dest_off;
+	      code_loc->object = loc->object;
+	      code_loc->shndx = ppc_object->get_opd_ent(loc->offset, &dest_off);
+	      code_loc->offset = dest_off;
+	      return code_loc;
+	    }
+	}
+
+    }
+  return NULL;
+}
+
 // Scan relocations for a section.
 
 template<int size, bool big_endian>
Index: gold/arm.cc
===================================================================
RCS file: /cvs/src/src/gold/arm.cc,v
retrieving revision 1.161
diff -u -p -r1.161 arm.cc
--- gold/arm.cc	9 Jan 2013 15:27:24 -0000	1.161
+++ gold/arm.cc	6 Mar 2013 09:51:11 -0000
@@ -2938,6 +2938,7 @@ const Target::Target_info Target_arm<big
   false,		// has_make_symbol
   false,		// has_resolve
   false,		// has_code_fill
+  false,		// has_func_descriptors
   true,			// is_default_stack_executable
   false,		// can_icf_inline_merge_sections
   '\0',			// wrap_char
@@ -12199,6 +12200,7 @@ const Target::Target_info Target_arm_nac
   false,		// has_make_symbol
   false,		// has_resolve
   false,		// has_code_fill
+  false,		// has_func_descriptors
   true,			// is_default_stack_executable
   false,		// can_icf_inline_merge_sections
   '\0',			// wrap_char
Index: gold/i386.cc
===================================================================
RCS file: /cvs/src/src/gold/i386.cc,v
retrieving revision 1.152
diff -u -p -r1.152 i386.cc
--- gold/i386.cc	2 Nov 2012 19:50:36 -0000	1.152
+++ gold/i386.cc	6 Mar 2013 09:51:11 -0000
@@ -843,6 +843,7 @@ const Target::Target_info Target_i386::i
   false,		// has_make_symbol
   false,		// has_resolve
   true,			// has_code_fill
+  false,		// has_func_descriptors
   true,			// is_default_stack_executable
   true,			// can_icf_inline_merge_sections
   '\0',			// wrap_char
@@ -3947,6 +3948,7 @@ const Target::Target_info Target_i386_na
   false,		// has_make_symbol
   false,		// has_resolve
   true,			// has_code_fill
+  false,		// has_func_descriptors
   true,			// is_default_stack_executable
   true,			// can_icf_inline_merge_sections
   '\0',			// wrap_char
Index: gold/sparc.cc
===================================================================
RCS file: /cvs/src/src/gold/sparc.cc,v
retrieving revision 1.64
diff -u -p -r1.64 sparc.cc
--- gold/sparc.cc	1 Nov 2012 23:27:00 -0000	1.64
+++ gold/sparc.cc	6 Mar 2013 09:51:12 -0000
@@ -469,6 +469,7 @@ Target::Target_info Target_sparc<32, tru
   false,		// has_make_symbol
   false,		// has_resolve
   false,		// has_code_fill
+  false,		// has_func_descriptors
   true,			// is_default_stack_executable
   false,		// can_icf_inline_merge_sections
   '\0',			// wrap_char
@@ -495,6 +496,7 @@ Target::Target_info Target_sparc<64, tru
   false,		// has_make_symbol
   false,		// has_resolve
   false,		// has_code_fill
+  false,		// has_func_descriptors
   true,			// is_default_stack_executable
   false,		// can_icf_inline_merge_sections
   '\0',			// wrap_char
Index: gold/tilegx.cc
===================================================================
RCS file: /cvs/src/src/gold/tilegx.cc,v
retrieving revision 1.5
diff -u -p -r1.5 tilegx.cc
--- gold/tilegx.cc	1 Nov 2012 23:27:00 -0000	1.5
+++ gold/tilegx.cc	6 Mar 2013 09:51:12 -0000
@@ -667,6 +667,7 @@ const Target::Target_info Target_tilegx<
   false,                // has_make_symbol
   false,                // has_resolve
   false,                // has_code_fill
+  false,		// has_func_descriptors
   true,                 // is_default_stack_executable
   false,                // can_icf_inline_merge_sections
   '\0',                 // wrap_char
@@ -693,6 +694,7 @@ const Target::Target_info Target_tilegx<
   false,                // has_make_symbol
   false,                // has_resolve
   false,                // has_code_fill
+  false,		// has_func_descriptors
   true,                 // is_default_stack_executable
   false,                // can_icf_inline_merge_sections
   '\0',                 // wrap_char
@@ -719,6 +721,7 @@ const Target::Target_info Target_tilegx<
   false,                // has_make_symbol
   false,                // has_resolve
   false,                // has_code_fill
+  false,		// has_func_descriptors
   true,                 // is_default_stack_executable
   false,                // can_icf_inline_merge_sections
   '\0',                 // wrap_char
@@ -745,6 +748,7 @@ const Target::Target_info Target_tilegx<
   false,                // has_make_symbol
   false,                // has_resolve
   false,                // has_code_fill
+  false,		// has_func_descriptors
   true,                 // is_default_stack_executable
   false,                // can_icf_inline_merge_sections
   '\0',                 // wrap_char
Index: gold/x86_64.cc
===================================================================
RCS file: /cvs/src/src/gold/x86_64.cc,v
retrieving revision 1.161
diff -u -p -r1.161 x86_64.cc
--- gold/x86_64.cc	20 Nov 2012 05:56:06 -0000	1.161
+++ gold/x86_64.cc	6 Mar 2013 09:51:12 -0000
@@ -993,6 +993,7 @@ const Target::Target_info Target_x86_64<
   false,		// has_make_symbol
   false,		// has_resolve
   true,			// has_code_fill
+  false,		// has_func_descriptors
   true,			// is_default_stack_executable
   true,			// can_icf_inline_merge_sections
   '\0',			// wrap_char
@@ -1019,6 +1020,7 @@ const Target::Target_info Target_x86_64<
   false,		// has_make_symbol
   false,		// has_resolve
   true,			// has_code_fill
+  false,		// has_func_descriptors
   true,			// is_default_stack_executable
   true,			// can_icf_inline_merge_sections
   '\0',			// wrap_char
@@ -4580,6 +4582,7 @@ const Target::Target_info Target_x86_64_
   false,		// has_make_symbol
   false,		// has_resolve
   true,			// has_code_fill
+  false,		// has_func_descriptors
   true,			// is_default_stack_executable
   true,			// can_icf_inline_merge_sections
   '\0',			// wrap_char
@@ -4606,6 +4609,7 @@ const Target::Target_info Target_x86_64_
   false,		// has_make_symbol
   false,		// has_resolve
   true,			// has_code_fill
+  false,		// has_func_descriptors
   true,			// is_default_stack_executable
   true,			// can_icf_inline_merge_sections
   '\0',			// wrap_char
Index: gold/testsuite/testfile.cc
===================================================================
RCS file: /cvs/src/src/gold/testsuite/testfile.cc,v
retrieving revision 1.24
diff -u -p -r1.24 testfile.cc
--- gold/testsuite/testfile.cc	1 Nov 2012 23:27:00 -0000	1.24
+++ gold/testsuite/testfile.cc	6 Mar 2013 09:51:12 -0000
@@ -93,6 +93,7 @@ const Target::Target_info Target_test<si
   false,				// has_make_symbol
   false,				// has_resolve
   false,				// has_code_fill
+  false,				// has_func_descriptors
   false,				// is_default_stack_executable
   false,				// can_icf_inline_merge_sections
   '\0',					// wrap_char

-- 
Alan Modra
Australia Development Lab, IBM


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]