Correct handling of addends in merged sections.
authorIan Lance Taylor <iant@google.com>
Sat, 6 Oct 2007 05:40:44 +0000 (05:40 +0000)
committerIan Lance Taylor <iant@google.com>
Sat, 6 Oct 2007 05:40:44 +0000 (05:40 +0000)
gold/object.cc
gold/object.h

index 2dbd0f2..9986383 100644 (file)
@@ -586,6 +586,9 @@ Sized_relobj<size, big_endian>::do_finalize_local_symbols(unsigned int index,
       unsigned int shndx = sym.get_st_shndx();
       lv.set_input_shndx(shndx);
 
+      if (sym.get_st_type() == elfcpp::STT_SECTION)
+       lv.set_is_section_symbol();
+
       if (shndx >= elfcpp::SHN_LORESERVE)
        {
          if (shndx == elfcpp::SHN_ABS)
@@ -660,12 +663,14 @@ Sized_relobj<size, big_endian>::do_finalize_local_symbols(unsigned int index,
 }
 
 // Return the value of a local symbol defined in input section SHNDX,
-// with value VALUE, adding addend ADDEND.  This handles SHF_MERGE
-// sections.
+// with value VALUE, adding addend ADDEND.  IS_SECTION_SYMBOL
+// indicates whether the symbol is a section symbol.  This handles
+// SHF_MERGE sections.
 template<int size, bool big_endian>
 typename elfcpp::Elf_types<size>::Elf_Addr
 Sized_relobj<size, big_endian>::local_value(unsigned int shndx,
                                            Address value,
+                                           bool is_section_symbol,
                                            Address addend) const
 {
   const std::vector<Map_to_output>& mo(this->map_to_output());
@@ -673,7 +678,22 @@ Sized_relobj<size, big_endian>::local_value(unsigned int shndx,
   if (os == NULL)
     return addend;
   gold_assert(mo[shndx].offset == -1);
-  return os->output_address(this, shndx, value + addend);
+
+  // Do the mapping required by the output section.  If this is not a
+  // section symbol, then we want to map the symbol value, and then
+  // include the addend.  If this is a section symbol, then we need to
+  // include the addend to figure out where in the section we are,
+  // before we do the mapping.  This will do the right thing provided
+  // the assembler is careful to only convert a relocation in a merged
+  // section to a section symbol if there is a zero addend.  If the
+  // assembler does not do this, then in general we can't know what to
+  // do, because we can't distinguish the addend for the instruction
+  // format from the addend for the section offset.
+
+  if (is_section_symbol)
+    return os->output_address(this, shndx, value + addend);
+  else
+    return addend + os->output_address(this, shndx, value);
 }
 
 // Write out the local symbols.
index cc1d5b2..e4359ac 100644 (file)
@@ -487,8 +487,8 @@ class Symbol_value
   typedef typename elfcpp::Elf_types<size>::Elf_Addr Value;
 
   Symbol_value()
-    : output_symtab_index_(0), input_shndx_(0), needs_output_address_(false),
-      value_(0)
+    : output_symtab_index_(0), input_shndx_(0), is_section_symbol_(false),
+      needs_output_address_(false), value_(0)
   { }
 
   // Get the value of this symbol.  OBJECT is the object in which this
@@ -499,7 +499,8 @@ class Symbol_value
   {
     if (!this->needs_output_address_)
       return this->value_ + addend;
-    return object->local_value(this->input_shndx_, this->value_, addend);
+    return object->local_value(this->input_shndx_, this->value_,
+                              this->is_section_symbol_, addend);
   }
 
   // Set the value of this symbol in the output symbol table.
@@ -560,16 +561,23 @@ class Symbol_value
   set_input_shndx(unsigned int i)
   { this->input_shndx_ = i; }
 
+  // Record that this is a section symbol.
+  void
+  set_is_section_symbol()
+  { this->is_section_symbol_ = true; }
+
  private:
   // The index of this local symbol in the output symbol table.  This
   // will be -1 if the symbol should not go into the symbol table.
   unsigned int output_symtab_index_;
   // The section index in the input file in which this symbol is
   // defined.
-  unsigned int input_shndx_ : 31;
+  unsigned int input_shndx_ : 30;
+  // Whether this is a STT_SECTION symbol.
+  bool is_section_symbol_ : 1;
   // Whether getting the value of this symbol requires calling an
   // Output_section method.  For example, this will be true of a
-  // STT_SECTION symbol in a SHF_MERGE section.
+  // symbol in a SHF_MERGE section.
   bool needs_output_address_ : 1;
   // The value of the symbol.  If !needs_output_address_, this is the
   // value in the output file.  If needs_output_address_, this is the
@@ -660,10 +668,12 @@ class Sized_relobj : public Relobj
   }
 
   // Return the value of a local symbol define in input section SHNDX,
-  // with value VALUE, adding addend ADDEND.  This handles SHF_MERGE
-  // sections.
+  // with value VALUE, adding addend ADDEND.  IS_SECTION_SYMBOL
+  // indicates whether the symbol is a section symbol.  This handles
+  // SHF_MERGE sections.
   Address
-  local_value(unsigned int shndx, Address value, Address addend) const;
+  local_value(unsigned int shndx, Address value, bool is_section_symbol,
+             Address addend) const;
 
  private:
   // For convenience.