[gold] Error out when there is an access beyond the end of the merged section

Alexander Ivchenko aivchenk@gmail.com
Tue Jul 1 12:23:00 GMT 2014


Hi,


Currently, when there is an access beyond the end of the merged
section (I faced that situation when linking the object file with
badly-generated debug info), gold will crash with internal error:

>ld.gold --eh-frame-hdr  -shared -m elf_i386 RenderBox.o
>ld.gold: internal error in value_from_output_section, at binutils-2.24/gold/reloc.cc:1485

While gnu ld will warn us about it and finish the job:

>ld.bfd --eh-frame-hdr  -shared -m elf_i386 RenderBox.o
ld.bfd: RenderBox.o: access beyond end of merged section (1997144320)


Internal error is in any way a wrong thing here, because there is
clearly a problem with an object file itself. The following patch adds
an error message when gold sees an incorrect access in merged section,
e.g:

>ld-new  --eh-frame-hdr  -shared -m elf_i386 RenderBox.o
ld-new: error: RenderBox.o: access beyond end of merged section (1997144320)



diff --git a/gold/ChangeLog b/gold/ChangeLog
index 264f127..0b617ca 100644
--- a/gold/ChangeLog
+++ b/gold/ChangeLog
@@ -1,3 +1,13 @@
+2014-07-01  Alexander Ivchenko  <alexander.ivchenko@intel.com>
+
+ * merge.cc (Object_merge_map::get_output_offset): error out when we see
+ that there is an access beyond the end of the merged section.
+ * merge.h (Object_merge_map::get_output_offset): Add new argument.
+ (Merge_map::get_output_offset): Adjust
+ Object_merge_map::get_output_offset call with additional argument.
+ * reloc.cc (Merged_symbol_value<size>::value_from_output_section):
+ Ditto.
+
 2014-06-27  Alan Modra  <amodra@gmail.com>

  * symtab.cc (Symbol::should_add_dynsym_entry): Don't make inline.
diff --git a/gold/merge.cc b/gold/merge.cc
index 6d444e6..18f7420 100644
--- a/gold/merge.cc
+++ b/gold/merge.cc
@@ -145,7 +145,8 @@ bool
 Object_merge_map::get_output_offset(const Merge_map* merge_map,
     unsigned int shndx,
     section_offset_type input_offset,
-    section_offset_type* output_offset)
+    section_offset_type* output_offset,
+    const Relobj* relobj)
 {
   Input_merge_map* map = this->get_input_merge_map(shndx);
   if (map == NULL
@@ -174,7 +175,13 @@ Object_merge_map::get_output_offset(const
Merge_map* merge_map,

   if (input_offset - p->input_offset
       >= static_cast<section_offset_type>(p->length))
-    return false;
+    {
+      if (relobj == NULL)
+ return false;
+      else
+ relobj->error(_("access beyond end of merged section (%ld)"),
+      input_offset);
+    }

   *output_offset = p->output_offset;
   if (*output_offset != -1)
@@ -268,7 +275,7 @@ Merge_map::get_output_offset(const Relobj* object,
unsigned int shndx,
   if (object_merge_map == NULL)
     return false;
   return object_merge_map->get_output_offset(this, shndx, offset,
-     output_offset);
+     output_offset, NULL);
 }

 // Return whether this is the merge section for SHNDX in OBJECT.
diff --git a/gold/merge.h b/gold/merge.h
index b4fd8e1..6df9879 100644
--- a/gold/merge.h
+++ b/gold/merge.h
@@ -66,11 +66,15 @@ class Object_merge_map
   // to the offset in the output section; this will be -1 if the bytes
   // are not being copied to the output.  This returns true if the
   // mapping is known, false otherwise.  *OUTPUT_OFFSET is relative to
-  // the start of the merged data in the output section.
+  // the start of the merged data in the output section. If RELOBJ
+  // is not NULL, then failure to find the output offset is fatal, but in
+  // some cases we can gracefully finish the job by providing the error
+  // information.
   bool
   get_output_offset(const Merge_map*, unsigned int shndx,
     section_offset_type offset,
-    section_offset_type* output_offset);
+    section_offset_type* output_offset,
+    const Relobj* relobj);

   // Return whether this is the merge map for section SHNDX.
   bool
diff --git a/gold/reloc.cc b/gold/reloc.cc
index 115ab37..8f09fef 100644
--- a/gold/reloc.cc
+++ b/gold/reloc.cc
@@ -1476,7 +1476,8 @@ Merged_symbol_value<size>::value_from_output_section(
   section_offset_type output_offset;
   bool found = object->merge_map()->get_output_offset(NULL, input_shndx,
       input_offset,
-      &output_offset);
+      &output_offset,
+      object);

   // If this assertion fails, it means that some relocation was
   // against a portion of an input merge section which we didn't map




 Is it ok?

 --Alexander



More information about the Binutils mailing list