Correct handling of addends in merged sections.
This commit is contained in:
parent
15bed04447
commit
063f12a825
@ -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.
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user