Fix bug with relocation addends and merge sections with --icf.
authorCary Coutant <ccoutant@gmail.com>
Wed, 25 Apr 2018 04:57:37 +0000 (21:57 -0700)
committerCary Coutant <ccoutant@gmail.com>
Wed, 25 Apr 2018 05:13:56 +0000 (22:13 -0700)
During --icf processing, gold was incorrectly processing the relocation
addend for references to items in a merge section. PC-relative references
and other forms of reference with a biased base address require a
non-section local symbol, where the addend is purely the bias.

gold/
PR gold/20642
PR gold/22820
* gc.h (gc_process_relocs): Flag STT_SECTION symbols in symvec.
* icf.cc (get_section_contents): For merge sections, ignore the
addend for relocations against non-section symbols.

gold/ChangeLog
gold/gc.h
gold/icf.cc

index e38262e294d326aa9b17713d7f3cfd84a21365f8..26ccad19476cc6324f24f7a7866e8a55986f5d49 100644 (file)
@@ -1,3 +1,11 @@
+2018-04-24  Cary Coutant  <ccoutant@gmail.com>
+
+       PR gold/20642
+       PR gold/22820
+       * gc.h (gc_process_relocs): Flag STT_SECTION symbols in symvec.
+       * icf.cc (get_section_contents): For merge sections, ignore the
+       addend for relocations against non-section symbols.
+
 2018-04-24  Cary Coutant  <ccoutant@gmail.com>
 
        PR gold/16504
index 7c79c23aa955717a119a6a63cf6dcca44693e9e4..78ead4132f9a533c1963ff3e3b71db71cb713331 100644 (file)
--- a/gold/gc.h
+++ b/gold/gc.h
@@ -247,7 +247,12 @@ gc_process_relocs(
                (*secvec).push_back(Section_id(src_obj, dst_indx));
              else
                 (*secvec).push_back(Section_id(NULL, 0));
-              (*symvec).push_back(NULL);
+              // If the target of the relocation is an STT_SECTION symbol,
+              // make a note of that by storing -1 in the symbol vector.
+              if (lsym.get_st_type() == elfcpp::STT_SECTION)
+               (*symvec).push_back(reinterpret_cast<Symbol*>(-1));
+             else
+               (*symvec).push_back(NULL);
              (*addendvec).push_back(std::make_pair(
                                        static_cast<long long>(symvalue),
                                        static_cast<long long>(addend)));
index 62dade8616c35eecc04ad3f2f52b570d542dff58..378a56bc54e853c351c6074d0cabd711bd94f62b 100644 (file)
@@ -327,6 +327,16 @@ get_section_contents(bool first_iteration,
 
       for (; it_v != v.end(); ++it_v, ++it_s, ++it_a, ++it_o, ++it_addend_size)
         {
+         Symbol* gsym = *it_s;
+         bool is_section_symbol = false;
+
+         // A -1 value in the symbol vector indicates a local section symbol.
+         if (gsym == reinterpret_cast<Symbol*>(-1))
+           {
+             is_section_symbol = true;
+             gsym = NULL;
+           }
+
          if (first_iteration
              && it_v->first != NULL)
            {
@@ -354,7 +364,7 @@ get_section_contents(bool first_iteration,
 
          // It would be nice if we could use format macros in inttypes.h
          // here but there are not in ISO/IEC C++ 1998.
-          snprintf(addend_str, sizeof(addend_str), "%llx %llx %llux",
+          snprintf(addend_str, sizeof(addend_str), "%llx %llx %llx",
                    static_cast<long long>((*it_a).first),
                   static_cast<long long>((*it_a).second),
                   static_cast<unsigned long long>(*it_o));
@@ -367,8 +377,8 @@ get_section_contents(bool first_iteration,
              if (first_iteration)
                 {
                  // If the symbol name is available, use it.
-                  if ((*it_s) != NULL)
-                      buffer.append((*it_s)->name());
+                  if (gsym != NULL)
+                      buffer.append(gsym->name());
                   // Append the addend.
                   buffer.append(addend_str);
                   buffer.append("@");
@@ -395,10 +405,10 @@ get_section_contents(bool first_iteration,
             symtab->icf()->section_to_int_map();
           Icf::Uniq_secn_id_map::iterator section_id_map_it =
             section_id_map.find(reloc_secn);
-          bool is_sym_preemptible = (*it_s != NULL
-                                    && !(*it_s)->is_from_dynobj()
-                                    && !(*it_s)->is_undefined()
-                                    && (*it_s)->is_preemptible());
+          bool is_sym_preemptible = (gsym != NULL
+                                    && !gsym->is_from_dynobj()
+                                    && !gsym->is_undefined()
+                                    && gsym->is_preemptible());
           if (!is_sym_preemptible
               && section_id_map_it != section_id_map.end())
             {
@@ -436,27 +446,41 @@ get_section_contents(bool first_iteration,
                   uint64_t entsize =
                     (it_v->first)->section_entsize(it_v->second);
                  long long offset = it_a->first;
-                 // Handle SHT_RELA and SHT_REL addends, only one of these
-                 // addends exists.
-                 // Get the SHT_RELA addend.  For RELA relocations, we have
-                 // the addend from the relocation.
-                 uint64_t reloc_addend_value = it_a->second;
-
-                 // Handle SHT_REL addends.
-                 // For REL relocations, we need to fetch the addend from the
-                 // section contents.
-                  const unsigned char* reloc_addend_ptr =
-                   contents + static_cast<unsigned long long>(*it_o);
-
-                 // Update the addend value with the SHT_REL addend if
-                 // available.
-                 get_rel_addend(reloc_addend_ptr, *it_addend_size,
-                                &reloc_addend_value);
-
-                 // Ignore the addend when it is a negative value.  See the
-                 // comments in Merged_symbol_value::value in object.h.
-                 if (reloc_addend_value < 0xffffff00)
-                   offset = offset + reloc_addend_value;
+
+                 // Handle SHT_RELA and SHT_REL addends. Only one of these
+                 // addends exists. When pointing to a merge section, the
+                 // addend only matters if it's relative to a section
+                 // symbol. In order to unambiguously identify the target
+                 // of the relocation, the compiler (and assembler) must use
+                 // a local non-section symbol unless Symbol+Addend does in
+                 // fact point directly to the target. (In other words,
+                 // a bias for a pc-relative reference or a non-zero based
+                 // access forces the use of a local symbol, and the addend
+                 // is used only to provide that bias.)
+                 uint64_t reloc_addend_value = 0;
+                 if (is_section_symbol)
+                   {
+                     // Get the SHT_RELA addend.  For RELA relocations,
+                     // we have the addend from the relocation.
+                     reloc_addend_value = it_a->second;
+
+                     // Handle SHT_REL addends.
+                     // For REL relocations, we need to fetch the addend
+                     // from the section contents.
+                     const unsigned char* reloc_addend_ptr =
+                       contents + static_cast<unsigned long long>(*it_o);
+
+                     // Update the addend value with the SHT_REL addend if
+                     // available.
+                     get_rel_addend(reloc_addend_ptr, *it_addend_size,
+                                    &reloc_addend_value);
+
+                     // Ignore the addend when it is a negative value.
+                     // See the comments in Merged_symbol_value::value
+                     // in object.h.
+                     if (reloc_addend_value < 0xffffff00)
+                       offset = offset + reloc_addend_value;
+                   }
 
                   section_size_type secn_len;
 
@@ -517,10 +541,10 @@ get_section_contents(bool first_iteration,
                     }
                  buffer.append("@");
                 }
-              else if ((*it_s) != NULL)
+              else if (gsym != NULL)
                 {
                   // If symbol name is available use that.
-                  buffer.append((*it_s)->name());
+                  buffer.append(gsym->name());
                   // Append the addend.
                   buffer.append(addend_str);
                   buffer.append("@");