PR 6658
authorIan Lance Taylor <ian@airs.com>
Thu, 24 Jul 2008 01:24:50 +0000 (01:24 +0000)
committerIan Lance Taylor <ian@airs.com>
Thu, 24 Jul 2008 01:24:50 +0000 (01:24 +0000)
* object.h (Merged_symbol_value::value): Do our best to handle a
negative addend.

gold/ChangeLog
gold/object.h

index dca8a51e3d03b3d39cc2d7a9aaa5203086d3efaf..a1458995d3010b876de59bc6b1bd6bd2006d1dab 100644 (file)
@@ -1,5 +1,9 @@
 2008-07-23  Ian Lance Taylor  <iant@google.com>
 
+       PR 6658
+       * object.h (Merged_symbol_value::value): Do our best to handle a
+       negative addend.
+
        PR 6647
        * script.cc (Version_script_info::get_versions): Don't add empty
        version tag to return value.
index 7334492fb237a5a1208996a4f546693cc14ab318..8ddd68970a3d548cb853e2d43fa9cad488dc1545 100644 (file)
@@ -822,13 +822,36 @@ class Merged_symbol_value
   Value
   value(const Relobj* object, unsigned int input_shndx, Value addend) const
   {
-    Value input_offset = this->input_value_ + addend;
+    // This is a relocation against a section symbol.  ADDEND is the
+    // offset in the section.  The result should be the start of some
+    // merge area.  If the object file wants something else, it should
+    // use a regular symbol rather than a section symbol.
+    // Unfortunately, PR 6658 shows a case in which the object file
+    // refers to the section symbol, but uses a negative ADDEND to
+    // compensate for a PC relative reloc.  We can't handle the
+    // general case.  However, we can handle the special case of a
+    // negative addend, by assuming that it refers to the start of the
+    // section.  Of course, that means that we have to guess when
+    // ADDEND is negative.  It is normal to see a 32-bit value here
+    // even when the template parameter size is 64, as 64-bit object
+    // file formats have 32-bit relocations.  We know this is a merge
+    // section, so we know it has to fit into memory.  So we assume
+    // that we won't see a value larger than a large 32-bit unsigned
+    // value.  This will break objects with very very large merge
+    // sections; they probably break in other ways anyhow.
+    Value input_offset = this->input_value_;
+    if (addend < 0xffffff00)
+      {
+       input_offset += addend;
+       addend = 0;
+      }
     typename Output_addresses::const_iterator p =
       this->output_addresses_.find(input_offset);
     if (p != this->output_addresses_.end())
-      return p->second;
+      return p->second + addend;
 
-    return this->value_from_output_section(object, input_shndx, input_offset);
+    return (this->value_from_output_section(object, input_shndx, input_offset)
+           + addend);
   }
 
  private: