From Cary Coutant: Fix handling of RELATIVE RELA relocs.

This commit is contained in:
Ian Lance Taylor 2007-12-07 19:32:59 +00:00
parent c68cf8ad10
commit e8c846c359
6 changed files with 200 additions and 111 deletions

View file

@ -811,8 +811,10 @@ Target_i386::Scan::local(const General_options&,
if (parameters->output_is_position_independent()) if (parameters->output_is_position_independent())
{ {
Reloc_section* rel_dyn = target->rel_dyn_section(layout); Reloc_section* rel_dyn = target->rel_dyn_section(layout);
rel_dyn->add_local(object, 0, elfcpp::R_386_RELATIVE, output_section, unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
data_shndx, reloc.get_r_offset()); rel_dyn->add_local_relative(object, r_sym, elfcpp::R_386_RELATIVE,
output_section, data_shndx,
reloc.get_r_offset());
} }
break; break;
@ -860,8 +862,11 @@ Target_i386::Scan::local(const General_options&,
if (parameters->output_is_position_independent()) if (parameters->output_is_position_independent())
{ {
Reloc_section* rel_dyn = target->rel_dyn_section(layout); Reloc_section* rel_dyn = target->rel_dyn_section(layout);
rel_dyn->add_local(object, 0, elfcpp::R_386_RELATIVE, unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
got, object->local_got_offset(r_sym)); rel_dyn->add_local_relative(object, r_sym,
elfcpp::R_386_RELATIVE,
got,
object->local_got_offset(r_sym));
} }
} }
} }
@ -955,9 +960,12 @@ Target_i386::Scan::local(const General_options&,
&& parameters->output_is_shared()) && parameters->output_is_shared())
{ {
Reloc_section* rel_dyn = target->rel_dyn_section(layout); Reloc_section* rel_dyn = target->rel_dyn_section(layout);
rel_dyn->add_local(object, 0, elfcpp::R_386_RELATIVE, unsigned int r_sym
output_section, data_shndx, = elfcpp::elf_r_sym<32>(reloc.get_r_info());
reloc.get_r_offset()); rel_dyn->add_local_relative(object, r_sym,
elfcpp::R_386_RELATIVE,
output_section, data_shndx,
reloc.get_r_offset());
} }
// Create a GOT entry for the tp-relative offset. // Create a GOT entry for the tp-relative offset.
Output_data_got<32, false>* got Output_data_got<32, false>* got
@ -1070,9 +1078,9 @@ Target_i386::Scan::global(const General_options& options,
&& gsym->can_use_relative_reloc(false)) && gsym->can_use_relative_reloc(false))
{ {
Reloc_section* rel_dyn = target->rel_dyn_section(layout); Reloc_section* rel_dyn = target->rel_dyn_section(layout);
rel_dyn->add_local(object, 0, elfcpp::R_386_RELATIVE, rel_dyn->add_global_relative(gsym, elfcpp::R_386_RELATIVE,
output_section, data_shndx, output_section, object,
reloc.get_r_offset()); data_shndx, reloc.get_r_offset());
} }
else else
{ {
@ -1136,12 +1144,8 @@ Target_i386::Scan::global(const General_options& options,
else else
{ {
if (got->add_global(gsym)) if (got->add_global(gsym))
{ rel_dyn->add_global_relative(gsym, elfcpp::R_386_RELATIVE,
rel_dyn->add_local(object, 0, elfcpp::R_386_RELATIVE, got, gsym->got_offset());
got, gsym->got_offset());
// Make sure we write the link-time value to the GOT.
gsym->set_needs_value_in_got();
}
} }
} }
} }
@ -1264,9 +1268,10 @@ Target_i386::Scan::global(const General_options& options,
&& parameters->output_is_shared()) && parameters->output_is_shared())
{ {
Reloc_section* rel_dyn = target->rel_dyn_section(layout); Reloc_section* rel_dyn = target->rel_dyn_section(layout);
rel_dyn->add_local(object, 0, elfcpp::R_386_RELATIVE, rel_dyn->add_global_relative(gsym, elfcpp::R_386_RELATIVE,
output_section, data_shndx, output_section, object,
reloc.get_r_offset()); data_shndx,
reloc.get_r_offset());
} }
// Create a GOT entry for the tp-relative offset. // Create a GOT entry for the tp-relative offset.
Output_data_got<32, false>* got Output_data_got<32, false>* got

View file

@ -512,13 +512,14 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
Symbol* gsym, Symbol* gsym,
unsigned int type, unsigned int type,
Output_data* od, Output_data* od,
Address address) Address address,
bool is_relative)
: address_(address), local_sym_index_(GSYM_CODE), type_(type), : address_(address), local_sym_index_(GSYM_CODE), type_(type),
shndx_(INVALID_CODE) is_relative_(is_relative), shndx_(INVALID_CODE)
{ {
this->u1_.gsym = gsym; this->u1_.gsym = gsym;
this->u2_.od = od; this->u2_.od = od;
if (dynamic) if (dynamic && !is_relative)
gsym->set_needs_dynsym_entry(); gsym->set_needs_dynsym_entry();
} }
@ -528,14 +529,15 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
unsigned int type, unsigned int type,
Relobj* relobj, Relobj* relobj,
unsigned int shndx, unsigned int shndx,
Address address) Address address,
bool is_relative)
: address_(address), local_sym_index_(GSYM_CODE), type_(type), : address_(address), local_sym_index_(GSYM_CODE), type_(type),
shndx_(shndx) is_relative_(is_relative), shndx_(shndx)
{ {
gold_assert(shndx != INVALID_CODE); gold_assert(shndx != INVALID_CODE);
this->u1_.gsym = gsym; this->u1_.gsym = gsym;
this->u2_.relobj = relobj; this->u2_.relobj = relobj;
if (dynamic) if (dynamic && !is_relative)
gsym->set_needs_dynsym_entry(); gsym->set_needs_dynsym_entry();
} }
@ -547,15 +549,16 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
unsigned int local_sym_index, unsigned int local_sym_index,
unsigned int type, unsigned int type,
Output_data* od, Output_data* od,
Address address) Address address,
bool is_relative)
: address_(address), local_sym_index_(local_sym_index), type_(type), : address_(address), local_sym_index_(local_sym_index), type_(type),
shndx_(INVALID_CODE) is_relative_(is_relative), shndx_(INVALID_CODE)
{ {
gold_assert(local_sym_index != GSYM_CODE gold_assert(local_sym_index != GSYM_CODE
&& local_sym_index != INVALID_CODE); && local_sym_index != INVALID_CODE);
this->u1_.relobj = relobj; this->u1_.relobj = relobj;
this->u2_.od = od; this->u2_.od = od;
if (dynamic && local_sym_index > 0) if (dynamic && !is_relative)
relobj->set_needs_output_dynsym_entry(local_sym_index); relobj->set_needs_output_dynsym_entry(local_sym_index);
} }
@ -565,16 +568,17 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
unsigned int local_sym_index, unsigned int local_sym_index,
unsigned int type, unsigned int type,
unsigned int shndx, unsigned int shndx,
Address address) Address address,
bool is_relative)
: address_(address), local_sym_index_(local_sym_index), type_(type), : address_(address), local_sym_index_(local_sym_index), type_(type),
shndx_(shndx) is_relative_(is_relative), shndx_(shndx)
{ {
gold_assert(local_sym_index != GSYM_CODE gold_assert(local_sym_index != GSYM_CODE
&& local_sym_index != INVALID_CODE); && local_sym_index != INVALID_CODE);
gold_assert(shndx != INVALID_CODE); gold_assert(shndx != INVALID_CODE);
this->u1_.relobj = relobj; this->u1_.relobj = relobj;
this->u2_.relobj = relobj; this->u2_.relobj = relobj;
if (dynamic && local_sym_index > 0) if (dynamic && !is_relative)
relobj->set_needs_output_dynsym_entry(local_sym_index); relobj->set_needs_output_dynsym_entry(local_sym_index);
} }
@ -587,7 +591,7 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
Output_data* od, Output_data* od,
Address address) Address address)
: address_(address), local_sym_index_(SECTION_CODE), type_(type), : address_(address), local_sym_index_(SECTION_CODE), type_(type),
shndx_(INVALID_CODE) is_relative_(false), shndx_(INVALID_CODE)
{ {
this->u1_.os = os; this->u1_.os = os;
this->u2_.od = od; this->u2_.od = od;
@ -603,7 +607,7 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
unsigned int shndx, unsigned int shndx,
Address address) Address address)
: address_(address), local_sym_index_(SECTION_CODE), type_(type), : address_(address), local_sym_index_(SECTION_CODE), type_(type),
shndx_(shndx) is_relative_(false), shndx_(shndx)
{ {
gold_assert(shndx != INVALID_CODE); gold_assert(shndx != INVALID_CODE);
this->u1_.os = os; this->u1_.os = os;
@ -685,8 +689,8 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::write_rel(
else if (this->u2_.od != NULL) else if (this->u2_.od != NULL)
address += this->u2_.od->address(); address += this->u2_.od->address();
wr->put_r_offset(address); wr->put_r_offset(address);
wr->put_r_info(elfcpp::elf_r_info<size>(this->get_symbol_index(), unsigned int sym_index = this->is_relative_ ? 0 : this->get_symbol_index();
this->type_)); wr->put_r_info(elfcpp::elf_r_info<size>(sym_index, this->type_));
} }
// Write out a Rel relocation. // Write out a Rel relocation.
@ -700,6 +704,24 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::write(
this->write_rel(&orel); this->write_rel(&orel);
} }
// Get the value of the symbol referred to by a Rel relocation.
template<bool dynamic, int size, bool big_endian>
typename elfcpp::Elf_types<size>::Elf_Addr
Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::symbol_value() const
{
if (this->local_sym_index_ == GSYM_CODE)
{
const Sized_symbol<size>* sym;
sym = static_cast<const Sized_symbol<size>*>(this->u1_.gsym);
return sym->value();
}
gold_assert(this->local_sym_index_ != SECTION_CODE
&& this->local_sym_index_ != INVALID_CODE);
const Sized_relobj<size, big_endian>* relobj = this->u1_.relobj;
return relobj->local_symbol_value(this->local_sym_index_);
}
// Write out a Rela relocation. // Write out a Rela relocation.
template<bool dynamic, int size, bool big_endian> template<bool dynamic, int size, bool big_endian>
@ -709,7 +731,10 @@ Output_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>::write(
{ {
elfcpp::Rela_write<size, big_endian> orel(pov); elfcpp::Rela_write<size, big_endian> orel(pov);
this->rel_.write_rel(&orel); this->rel_.write_rel(&orel);
orel.put_r_addend(this->addend_); Addend addend = this->addend_;
if (rel_.is_relative())
addend += rel_.symbol_value();
orel.put_r_addend(addend);
} }
// Output_data_reloc_base methods. // Output_data_reloc_base methods.
@ -775,24 +800,16 @@ Output_data_got<size, big_endian>::Got_entry::write(unsigned char* pov) const
{ {
case GSYM_CODE: case GSYM_CODE:
{ {
// If the symbol is resolved locally, we need to write out the
// link-time value, which will be relocated dynamically by a
// RELATIVE relocation.
Symbol* gsym = this->u_.gsym; Symbol* gsym = this->u_.gsym;
Sized_symbol<size>* sgsym;
// If the symbol is resolved locally, we need to write out its // This cast is a bit ugly. We don't want to put a
// value. Otherwise we just write zero. The target code is // virtual method in Symbol, because we want Symbol to be
// responsible for creating a relocation entry to fill in the // as small as possible.
// value at runtime. For non-preemptible symbols in a shared sgsym = static_cast<Sized_symbol<size>*>(gsym);
// library, the target will need to record whether or not the val = sgsym->value();
// value should be written (e.g., it may use a RELATIVE
// relocation type).
if (gsym->final_value_is_known() || gsym->needs_value_in_got())
{
Sized_symbol<size>* sgsym;
// This cast is a bit ugly. We don't want to put a
// virtual method in Symbol, because we want Symbol to be
// as small as possible.
sgsym = static_cast<Sized_symbol<size>*>(gsym);
val = sgsym->value();
}
} }
break; break;

View file

@ -703,20 +703,20 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
// A reloc against a global symbol. // A reloc against a global symbol.
Output_reloc(Symbol* gsym, unsigned int type, Output_data* od, Output_reloc(Symbol* gsym, unsigned int type, Output_data* od,
Address address); Address address, bool is_relative);
Output_reloc(Symbol* gsym, unsigned int type, Relobj* relobj, Output_reloc(Symbol* gsym, unsigned int type, Relobj* relobj,
unsigned int shndx, Address address); unsigned int shndx, Address address, bool is_relative);
// A reloc against a local symbol. // A reloc against a local symbol.
Output_reloc(Sized_relobj<size, big_endian>* relobj, Output_reloc(Sized_relobj<size, big_endian>* relobj,
unsigned int local_sym_index, unsigned int type, unsigned int local_sym_index, unsigned int type,
Output_data* od, Address address); Output_data* od, Address address, bool is_relative);
Output_reloc(Sized_relobj<size, big_endian>* relobj, Output_reloc(Sized_relobj<size, big_endian>* relobj,
unsigned int local_sym_index, unsigned int type, unsigned int local_sym_index, unsigned int type,
unsigned int shndx, Address address); unsigned int shndx, Address address, bool is_relative);
// A reloc against the STT_SECTION symbol of an output section. // A reloc against the STT_SECTION symbol of an output section.
@ -726,6 +726,16 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
Output_reloc(Output_section* os, unsigned int type, Relobj* relobj, Output_reloc(Output_section* os, unsigned int type, Relobj* relobj,
unsigned int shndx, Address address); unsigned int shndx, Address address);
// Return TRUE if this is a RELATIVE relocation.
bool
is_relative() const
{ return this->is_relative_; }
// Get the value of the symbol referred to by a Rel relocation.
Address
symbol_value() const;
// Write the reloc entry to an output view. // Write the reloc entry to an output view.
void void
write(unsigned char* pov) const; write(unsigned char* pov) const;
@ -780,7 +790,9 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
// for a global symbol, or INVALID_CODE for an uninitialized value. // for a global symbol, or INVALID_CODE for an uninitialized value.
unsigned int local_sym_index_; unsigned int local_sym_index_;
// The reloc type--a processor specific code. // The reloc type--a processor specific code.
unsigned int type_; unsigned int type_ : 31;
// True if the relocation is a RELATIVE relocation.
bool is_relative_ : 1;
// If the reloc address is an input section in an object, the // If the reloc address is an input section in an object, the
// section index. This is INVALID_CODE if the reloc address is // section index. This is INVALID_CODE if the reloc address is
// specified in some other way. // specified in some other way.
@ -805,31 +817,31 @@ class Output_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
// A reloc against a global symbol. // A reloc against a global symbol.
Output_reloc(Symbol* gsym, unsigned int type, Output_data* od, Output_reloc(Symbol* gsym, unsigned int type, Output_data* od,
Address address, Addend addend) Address address, Addend addend, bool is_relative)
: rel_(gsym, type, od, address), addend_(addend) : rel_(gsym, type, od, address, is_relative), addend_(addend)
{ } { }
Output_reloc(Symbol* gsym, unsigned int type, Relobj* relobj, Output_reloc(Symbol* gsym, unsigned int type, Relobj* relobj,
unsigned int shndx, Address address, Addend addend) unsigned int shndx, Address address, Addend addend,
: rel_(gsym, type, relobj, shndx, address), addend_(addend) bool is_relative)
: rel_(gsym, type, relobj, shndx, address, is_relative), addend_(addend)
{ } { }
// A reloc against a local symbol. // A reloc against a local symbol.
Output_reloc(Sized_relobj<size, big_endian>* relobj, Output_reloc(Sized_relobj<size, big_endian>* relobj,
unsigned int local_sym_index, unsigned int local_sym_index, unsigned int type,
unsigned int type, Output_data* od, Address address, Output_data* od, Address address,
Addend addend) Addend addend, bool is_relative)
: rel_(relobj, local_sym_index, type, od, address), addend_(addend) : rel_(relobj, local_sym_index, type, od, address, is_relative),
addend_(addend)
{ } { }
Output_reloc(Sized_relobj<size, big_endian>* relobj, Output_reloc(Sized_relobj<size, big_endian>* relobj,
unsigned int local_sym_index, unsigned int local_sym_index, unsigned int type,
unsigned int type, unsigned int shndx, Address address,
unsigned int shndx, Addend addend, bool is_relative)
Address address, : rel_(relobj, local_sym_index, type, shndx, address, is_relative),
Addend addend)
: rel_(relobj, local_sym_index, type, shndx, address),
addend_(addend) addend_(addend)
{ } { }
@ -928,12 +940,27 @@ class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
void void
add_global(Symbol* gsym, unsigned int type, Output_data* od, Address address) add_global(Symbol* gsym, unsigned int type, Output_data* od, Address address)
{ this->add(od, Output_reloc_type(gsym, type, od, address)); } { this->add(od, Output_reloc_type(gsym, type, od, address, false)); }
void void
add_global(Symbol* gsym, unsigned int type, Output_data* od, Relobj* relobj, add_global(Symbol* gsym, unsigned int type, Output_data* od, Relobj* relobj,
unsigned int shndx, Address address) unsigned int shndx, Address address)
{ this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address)); } { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
false)); }
// Add a RELATIVE reloc against a global symbol. The final relocation
// will not reference the symbol.
void
add_global_relative(Symbol* gsym, unsigned int type, Output_data* od,
Address address)
{ this->add(od, Output_reloc_type(gsym, type, od, address, true)); }
void
add_global_relative(Symbol* gsym, unsigned int type, Output_data* od,
Relobj* relobj, unsigned int shndx, Address address)
{ this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
true)); }
// Add a reloc against a local symbol. // Add a reloc against a local symbol.
@ -942,15 +969,30 @@ class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
unsigned int local_sym_index, unsigned int type, unsigned int local_sym_index, unsigned int type,
Output_data* od, Address address) Output_data* od, Address address)
{ this->add(od, Output_reloc_type(relobj, local_sym_index, type, od, { this->add(od, Output_reloc_type(relobj, local_sym_index, type, od,
address)); } address, false)); }
void void
add_local(Sized_relobj<size, big_endian>* relobj, add_local(Sized_relobj<size, big_endian>* relobj,
unsigned int local_sym_index, unsigned int type, unsigned int local_sym_index, unsigned int type,
Output_data* od, unsigned int shndx, Address address) Output_data* od, unsigned int shndx, Address address)
{ this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx, { this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
address)); } address, false)); }
// Add a RELATIVE reloc against a local symbol.
void
add_local_relative(Sized_relobj<size, big_endian>* relobj,
unsigned int local_sym_index, unsigned int type,
Output_data* od, Address address)
{ this->add(od, Output_reloc_type(relobj, local_sym_index, type, od,
address, true)); }
void
add_local_relative(Sized_relobj<size, big_endian>* relobj,
unsigned int local_sym_index, unsigned int type,
Output_data* od, unsigned int shndx, Address address)
{ this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
address, true)); }
// A reloc against the STT_SECTION symbol of an output section. // A reloc against the STT_SECTION symbol of an output section.
// OS is the Output_section that the relocation refers to; OD is // OS is the Output_section that the relocation refers to; OD is
@ -991,14 +1033,32 @@ class Output_data_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
void void
add_global(Symbol* gsym, unsigned int type, Output_data* od, add_global(Symbol* gsym, unsigned int type, Output_data* od,
Address address, Addend addend) Address address, Addend addend)
{ this->add(od, Output_reloc_type(gsym, type, od, address, addend)); } { this->add(od, Output_reloc_type(gsym, type, od, address, addend,
false)); }
void void
add_global(Symbol* gsym, unsigned int type, Output_data* od, Relobj* relobj, add_global(Symbol* gsym, unsigned int type, Output_data* od, Relobj* relobj,
unsigned int shndx, Address address, unsigned int shndx, Address address,
Addend addend) Addend addend)
{ this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address, { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
addend)); } addend, false)); }
// Add a RELATIVE reloc against a global symbol. The final output
// relocation will not reference the symbol, but we must keep the symbol
// information long enough to set the addend of the relocation correctly
// when it is written.
void
add_global_relative(Symbol* gsym, unsigned int type, Output_data* od,
Address address, Addend addend)
{ this->add(od, Output_reloc_type(gsym, type, od, address, addend, true)); }
void
add_global_relative(Symbol* gsym, unsigned int type, Output_data* od,
Relobj* relobj, unsigned int shndx, Address address,
Addend addend)
{ this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
addend, true)); }
// Add a reloc against a local symbol. // Add a reloc against a local symbol.
@ -1008,7 +1068,7 @@ class Output_data_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
Output_data* od, Address address, Addend addend) Output_data* od, Address address, Addend addend)
{ {
this->add(od, Output_reloc_type(relobj, local_sym_index, type, od, address, this->add(od, Output_reloc_type(relobj, local_sym_index, type, od, address,
addend)); addend, false));
} }
void void
@ -1018,7 +1078,28 @@ class Output_data_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
Addend addend) Addend addend)
{ {
this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx, this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
address, addend)); address, addend, false));
}
// Add a RELATIVE reloc against a local symbol.
void
add_local_relative(Sized_relobj<size, big_endian>* relobj,
unsigned int local_sym_index, unsigned int type,
Output_data* od, Address address, Addend addend)
{
this->add(od, Output_reloc_type(relobj, local_sym_index, type, od, address,
addend, true));
}
void
add_local_relative(Sized_relobj<size, big_endian>* relobj,
unsigned int local_sym_index, unsigned int type,
Output_data* od, unsigned int shndx, Address address,
Addend addend)
{
this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
address, addend, true));
} }
// A reloc against the STT_SECTION symbol of an output section. // A reloc against the STT_SECTION symbol of an output section.

View file

@ -70,7 +70,6 @@ Symbol::init_fields(const char* name, const char* version,
this->has_plt_offset_ = false; this->has_plt_offset_ = false;
this->has_warning_ = false; this->has_warning_ = false;
this->is_copied_from_dynobj_ = false; this->is_copied_from_dynobj_ = false;
this->needs_value_in_got_ = false;
} }
// Return the demangled version of the symbol's name, but only // Return the demangled version of the symbol's name, but only

View file

@ -541,19 +541,6 @@ class Symbol
set_is_copied_from_dynobj() set_is_copied_from_dynobj()
{ this->is_copied_from_dynobj_ = true; } { this->is_copied_from_dynobj_ = true; }
// Mark this symbol as needing its value written to the GOT even when
// the value is subject to dynamic relocation (e.g., when the target
// uses a RELATIVE relocation for the GOT entry).
void
set_needs_value_in_got()
{ this->needs_value_in_got_ = true; }
// Return whether this symbol needs its value written to the GOT even
// when the value is subject to dynamic relocation.
bool
needs_value_in_got() const
{ return this->needs_value_in_got_; }
protected: protected:
// Instances of this class should always be created at a specific // Instances of this class should always be created at a specific
// size. // size.
@ -730,9 +717,6 @@ class Symbol
// True if we are using a COPY reloc for this symbol, so that the // True if we are using a COPY reloc for this symbol, so that the
// real definition lives in a dynamic object. // real definition lives in a dynamic object.
bool is_copied_from_dynobj_ : 1; bool is_copied_from_dynobj_ : 1;
// True if the static value should be written to the GOT even
// when the final value is subject to dynamic relocation.
bool needs_value_in_got_ : 1;
}; };
// The parts of a symbol which are size specific. Using a template // The parts of a symbol which are size specific. Using a template

View file

@ -765,10 +765,13 @@ Target_x86_64::Scan::local(const General_options&,
// relocate it easily. // relocate it easily.
if (parameters->output_is_position_independent()) if (parameters->output_is_position_independent())
{ {
unsigned int r_sym = elfcpp::elf_r_sym<64>(reloc.get_r_info());
Reloc_section* rela_dyn = target->rela_dyn_section(layout); Reloc_section* rela_dyn = target->rela_dyn_section(layout);
rela_dyn->add_local(object, 0, elfcpp::R_X86_64_RELATIVE, rela_dyn->add_local_relative(object, r_sym,
output_section, data_shndx, elfcpp::R_X86_64_RELATIVE,
reloc.get_r_offset(), 0); output_section, data_shndx,
reloc.get_r_offset(),
reloc.get_r_addend());
} }
break; break;
@ -831,8 +834,10 @@ Target_x86_64::Scan::local(const General_options&,
Reloc_section* rela_dyn = target->rela_dyn_section(layout); Reloc_section* rela_dyn = target->rela_dyn_section(layout);
// R_X86_64_RELATIVE assumes a 64-bit relocation. // R_X86_64_RELATIVE assumes a 64-bit relocation.
if (r_type != elfcpp::R_X86_64_GOT32) if (r_type != elfcpp::R_X86_64_GOT32)
rela_dyn->add_local(object, 0, elfcpp::R_X86_64_RELATIVE, rela_dyn->add_local_relative(object, r_sym,
got, object->local_got_offset(r_sym), 0); elfcpp::R_X86_64_RELATIVE, got,
object->local_got_offset(r_sym),
0);
else else
rela_dyn->add_local(object, r_sym, r_type, rela_dyn->add_local(object, r_sym, r_type,
got, object->local_got_offset(r_sym), 0); got, object->local_got_offset(r_sym), 0);
@ -1012,9 +1017,10 @@ Target_x86_64::Scan::global(const General_options& options,
&& gsym->can_use_relative_reloc(false)) && gsym->can_use_relative_reloc(false))
{ {
Reloc_section* rela_dyn = target->rela_dyn_section(layout); Reloc_section* rela_dyn = target->rela_dyn_section(layout);
rela_dyn->add_local(object, 0, elfcpp::R_X86_64_RELATIVE, rela_dyn->add_global_relative(gsym, elfcpp::R_X86_64_RELATIVE,
output_section, data_shndx, output_section, object,
reloc.get_r_offset(), 0); data_shndx, reloc.get_r_offset(),
reloc.get_r_addend());
} }
else else
{ {
@ -1076,12 +1082,9 @@ Target_x86_64::Scan::global(const General_options& options,
else else
{ {
if (got->add_global(gsym)) if (got->add_global(gsym))
{ rela_dyn->add_global_relative(gsym,
rela_dyn->add_local(object, 0, elfcpp::R_X86_64_RELATIVE, elfcpp::R_X86_64_RELATIVE,
got, gsym->got_offset(), 0); got, gsym->got_offset(), 0);
// Make sure we write the link-time value to the GOT.
gsym->set_needs_value_in_got();
}
} }
} }
// For GOTPLT64, we also need a PLT entry (but only if the // For GOTPLT64, we also need a PLT entry (but only if the