[PATCH][GOLD] Handle .ARM.exidx sections in garbage collection.

Doug Kwan (關振德) dougkwan@google.com
Mon Jan 11 06:20:00 GMT 2010


Hi,

    This patch mainly add code to handle .ARM.exidx sections properly
in garbage collection.  These sections contain information about
unwinding and are linked to text sections in the input objects.   When
we look at a text section for reachable sections, we need to include
the associated .ARM.exidx section if there is one.   This patch also
fixes the generation of symbols __exdix_start and __exidx_end.

-Doug

2010-01-10  Doug Kwan  <dougkwan@google.com>

        * arm.cc (Arm_relobj::do_gc_proccess_relocs): New method.
        (Target_arm::do_finalize_sections): Only define __exidx_start and
        __exidx_end if these have not been defined already.  Also use default
        visibility for these symbols to match behaviour of GNU ld.
-------------- next part --------------
Index: gold/arm.cc
===================================================================
RCS file: /cvs/src/src/gold/arm.cc,v
retrieving revision 1.49
diff -u -p -r1.49 arm.cc
--- gold/arm.cc	9 Jan 2010 01:55:14 -0000	1.49
+++ gold/arm.cc	11 Jan 2010 05:32:05 -0000
@@ -1178,6 +1178,10 @@ class Arm_relobj : public Sized_relobj<3
   void
   do_read_symbols(Read_symbols_data* sd);
 
+  // Process relocs for garbage collection.
+  void
+  do_gc_process_relocs(Symbol_table*, Layout*, Read_relocs_data*);
+
  private:
   // List of stub tables.
   typedef std::vector<Stub_table<big_endian>*> Stub_table_list;
@@ -4235,6 +4239,51 @@ Arm_relobj<big_endian>::do_read_symbols(
     read_arm_attributes_section<big_endian>(this, sd); 
 }
 
+// Process relocations for garbage collection.  The ARM target uses .ARM.exidx
+// sections for unwinding.  These sections are referenced implicitly by 
+// text sections linked in the section headers.  If we ignore these implict
+// references, the .ARM.exidx sections and any .ARM.extab sections they use
+// will be garbage-collected incorrectly.  Hence we override the same function
+// in the base class to handle these implicit references.
+
+template<bool big_endian>
+void
+Arm_relobj<big_endian>::do_gc_process_relocs(Symbol_table* symtab,
+					     Layout* layout,
+					     Read_relocs_data* rd)
+{
+  // First, call base class method to process relocations in this object.
+  Sized_relobj<32, big_endian>::do_gc_process_relocs(symtab, layout, rd);
+
+  unsigned int shnum = this->shnum();
+  const unsigned int shdr_size = elfcpp::Elf_sizes<32>::shdr_size;
+  const unsigned char* pshdrs = this->get_view(this->elf_file()->shoff(),
+					       shnum * shdr_size,
+					       true, true);
+
+  // Scan section headers for sections of type SHT_ARM_EXIDX.  Add references
+  // to these from the linked text sections.
+  const unsigned char* ps = pshdrs + shdr_size;
+  for (unsigned int i = 1; i < shnum; ++i, ps += shdr_size)
+    {
+      elfcpp::Shdr<32, big_endian> shdr(ps);
+      if (shdr.get_sh_type() == elfcpp::SHT_ARM_EXIDX)
+	{
+	  // Found an .ARM.exidx section, add it to the set of reachable
+	  // sections from its linked text section.
+	  unsigned int text_shndx = this->adjust_shndx(shdr.get_sh_link());
+	  Section_id src_id(this, text_shndx);
+	  Section_id dst_id(this, i);
+	  Garbage_collection::Section_ref::iterator map_it
+	    = symtab->gc()->section_reloc_map().find(src_id);
+	  if (map_it == symtab->gc()->section_reloc_map().end())
+	    symtab->gc()->section_reloc_map()[src_id].insert(dst_id);
+          else
+	    map_it->second.insert(dst_id);
+	}
+    }
+}
+
 // Arm_dynobj methods.
 
 // Read the symbol information.
@@ -5076,17 +5125,27 @@ Target_arm<big_endian>::do_finalize_sect
       && exidx_section->type() == elfcpp::SHT_ARM_EXIDX
       && !parameters->options().relocatable())
     {
-      // Create __exidx_start and __exdix_end symbols.
-      symtab->define_in_output_data("__exidx_start", NULL,
-				    Symbol_table::PREDEFINED,
-				    exidx_section, 0, 0, elfcpp::STT_OBJECT,
-				    elfcpp::STB_GLOBAL, elfcpp::STV_HIDDEN, 0,
-				    false, false);
-      symtab->define_in_output_data("__exidx_end", NULL,
-				    Symbol_table::PREDEFINED,
-				    exidx_section, 0, 0, elfcpp::STT_OBJECT,
-				    elfcpp::STB_GLOBAL, elfcpp::STV_HIDDEN, 0,
-				    true, false);
+      // Create __exidx_start and __exdix_end symbols if they are not already
+      // defined in the output.
+      Symbol* sym = symtab->lookup("__exidx_start", NULL);
+      if (sym == NULL
+	  || sym->is_undefined()
+	  || sym->is_from_dynobj())
+	symtab->define_in_output_data("__exidx_start", NULL,
+				      Symbol_table::PREDEFINED,
+				      exidx_section, 0, 0, elfcpp::STT_OBJECT,
+				      elfcpp::STB_GLOBAL, elfcpp::STV_DEFAULT,
+				      0, false, false);
+
+      sym = symtab->lookup("__exidx_end", NULL);
+      if (sym == NULL
+	  || sym->is_undefined()
+	  || sym->is_from_dynobj())
+	symtab->define_in_output_data("__exidx_end", NULL,
+				      Symbol_table::PREDEFINED,
+				      exidx_section, 0, 0, elfcpp::STT_OBJECT,
+				      elfcpp::STB_GLOBAL, elfcpp::STV_DEFAULT,
+				      0, true, false);
 
       // For the ARM target, we need to add a PT_ARM_EXIDX segment for
       // the .ARM.exidx section.


More information about the Binutils mailing list