Support dynamic relocations against local section symbols.

This commit is contained in:
Ian Lance Taylor 2008-02-12 00:28:48 +00:00
parent 709d67f15a
commit dceae3c154
6 changed files with 302 additions and 85 deletions

View File

@ -898,9 +898,19 @@ Target_i386::Scan::local(const General_options&,
if (parameters->output_is_position_independent())
{
Reloc_section* rel_dyn = target->rel_dyn_section(layout);
if (lsym.get_st_type() != elfcpp::STT_SECTION)
{
unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
rel_dyn->add_local(object, r_sym, r_type, output_section, data_shndx,
reloc.get_r_offset());
rel_dyn->add_local(object, r_sym, r_type, output_section,
data_shndx, reloc.get_r_offset());
}
else
{
gold_assert(lsym.get_st_value() == 0);
rel_dyn->add_local_section(object, lsym.get_st_shndx(),
r_type, output_section,
data_shndx, reloc.get_r_offset());
}
}
break;
@ -1053,6 +1063,7 @@ Target_i386::Scan::local(const General_options&,
if (output_is_shared)
{
// We need to create a dynamic relocation.
gold_assert(lsym.get_st_type() != elfcpp::STT_SECTION);
unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
unsigned int dyn_r_type = (r_type == elfcpp::R_386_TLS_LE_32
? elfcpp::R_386_TLS_TPOFF32

View File

@ -884,12 +884,14 @@ Sized_relobj<size, big_endian>::do_count_local_symbols(Stringpool* pool,
if (shndx < shnum && mo[shndx].output_section == NULL)
{
lv.set_no_output_symtab_entry();
gold_assert(!lv.needs_output_dynsym_entry());
continue;
}
if (sym.get_st_type() == elfcpp::STT_SECTION)
{
lv.set_no_output_symtab_entry();
gold_assert(!lv.needs_output_dynsym_entry());
continue;
}

View File

@ -874,6 +874,7 @@ class Symbol_value
void
set_needs_output_dynsym_entry()
{
gold_assert(!this->is_section_symbol());
this->output_dynsym_index_ = 0;
}
@ -897,7 +898,8 @@ class Symbol_value
unsigned int
output_dynsym_index() const
{
gold_assert(this->output_dynsym_index_ != 0);
gold_assert(this->output_dynsym_index_ != 0
&& this->output_dynsym_index_ != -1U);
return this->output_dynsym_index_;
}
@ -924,7 +926,10 @@ class Symbol_value
// Record that this is a section symbol.
void
set_is_section_symbol()
{ this->is_section_symbol_ = true; }
{
gold_assert(!this->needs_output_dynsym_entry());
this->is_section_symbol_ = true;
}
// Record that this is a TLS symbol.
void

View File

@ -608,12 +608,14 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
Address address,
bool is_relative)
: address_(address), local_sym_index_(GSYM_CODE), type_(type),
is_relative_(is_relative), shndx_(INVALID_CODE)
is_relative_(is_relative), is_section_symbol_(false), shndx_(INVALID_CODE)
{
// this->type_ is a bitfield; make sure TYPE fits.
gold_assert(this->type_ == type);
this->u1_.gsym = gsym;
this->u2_.od = od;
if (dynamic && !is_relative)
gsym->set_needs_dynsym_entry();
if (dynamic)
this->set_needs_dynsym_index();
}
template<bool dynamic, int size, bool big_endian>
@ -625,13 +627,15 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
Address address,
bool is_relative)
: address_(address), local_sym_index_(GSYM_CODE), type_(type),
is_relative_(is_relative), shndx_(shndx)
is_relative_(is_relative), is_section_symbol_(false), shndx_(shndx)
{
gold_assert(shndx != INVALID_CODE);
// this->type_ is a bitfield; make sure TYPE fits.
gold_assert(this->type_ == type);
this->u1_.gsym = gsym;
this->u2_.relobj = relobj;
if (dynamic && !is_relative)
gsym->set_needs_dynsym_entry();
if (dynamic)
this->set_needs_dynsym_index();
}
// A reloc against a local symbol.
@ -643,16 +647,20 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
unsigned int type,
Output_data* od,
Address address,
bool is_relative)
bool is_relative,
bool is_section_symbol)
: address_(address), local_sym_index_(local_sym_index), type_(type),
is_relative_(is_relative), shndx_(INVALID_CODE)
is_relative_(is_relative), is_section_symbol_(is_section_symbol),
shndx_(INVALID_CODE)
{
gold_assert(local_sym_index != GSYM_CODE
&& local_sym_index != INVALID_CODE);
// this->type_ is a bitfield; make sure TYPE fits.
gold_assert(this->type_ == type);
this->u1_.relobj = relobj;
this->u2_.od = od;
if (dynamic && !is_relative)
relobj->set_needs_output_dynsym_entry(local_sym_index);
if (dynamic)
this->set_needs_dynsym_index();
}
template<bool dynamic, int size, bool big_endian>
@ -662,17 +670,21 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
unsigned int type,
unsigned int shndx,
Address address,
bool is_relative)
bool is_relative,
bool is_section_symbol)
: address_(address), local_sym_index_(local_sym_index), type_(type),
is_relative_(is_relative), shndx_(shndx)
is_relative_(is_relative), is_section_symbol_(is_section_symbol),
shndx_(shndx)
{
gold_assert(local_sym_index != GSYM_CODE
&& local_sym_index != INVALID_CODE);
gold_assert(shndx != INVALID_CODE);
// this->type_ is a bitfield; make sure TYPE fits.
gold_assert(this->type_ == type);
this->u1_.relobj = relobj;
this->u2_.relobj = relobj;
if (dynamic && !is_relative)
relobj->set_needs_output_dynsym_entry(local_sym_index);
if (dynamic)
this->set_needs_dynsym_index();
}
// A reloc against the STT_SECTION symbol of an output section.
@ -684,12 +696,16 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
Output_data* od,
Address address)
: address_(address), local_sym_index_(SECTION_CODE), type_(type),
is_relative_(false), shndx_(INVALID_CODE)
is_relative_(false), is_section_symbol_(true), shndx_(INVALID_CODE)
{
// this->type_ is a bitfield; make sure TYPE fits.
gold_assert(this->type_ == type);
this->u1_.os = os;
this->u2_.od = od;
if (dynamic)
os->set_needs_dynsym_index();
this->set_needs_dynsym_index();
else
os->set_needs_symtab_index();
}
template<bool dynamic, int size, bool big_endian>
@ -700,13 +716,59 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
unsigned int shndx,
Address address)
: address_(address), local_sym_index_(SECTION_CODE), type_(type),
is_relative_(false), shndx_(shndx)
is_relative_(false), is_section_symbol_(true), shndx_(shndx)
{
gold_assert(shndx != INVALID_CODE);
// this->type_ is a bitfield; make sure TYPE fits.
gold_assert(this->type_ == type);
this->u1_.os = os;
this->u2_.relobj = relobj;
if (dynamic)
this->set_needs_dynsym_index();
else
os->set_needs_symtab_index();
}
// Record that we need a dynamic symbol index for this relocation.
template<bool dynamic, int size, bool big_endian>
void
Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::
set_needs_dynsym_index()
{
if (this->is_relative_)
return;
switch (this->local_sym_index_)
{
case INVALID_CODE:
gold_unreachable();
case GSYM_CODE:
this->u1_.gsym->set_needs_dynsym_entry();
break;
case SECTION_CODE:
this->u1_.os->set_needs_dynsym_index();
break;
case 0:
break;
default:
{
const unsigned int lsi = this->local_sym_index_;
if (!this->is_section_symbol_)
this->u1_.relobj->set_needs_output_dynsym_entry(lsi);
else
{
section_offset_type dummy;
Output_section* os = this->u1_.relobj->output_section(lsi, &dummy);
gold_assert(os != NULL);
os->set_needs_dynsym_index();
}
}
break;
}
}
// Get the symbol index of a relocation.
@ -744,16 +806,47 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::get_symbol_index()
break;
default:
{
const unsigned int lsi = this->local_sym_index_;
if (!this->is_section_symbol_)
{
if (dynamic)
index = this->u1_.relobj->dynsym_index(this->local_sym_index_);
index = this->u1_.relobj->dynsym_index(lsi);
else
index = this->u1_.relobj->symtab_index(this->local_sym_index_);
index = this->u1_.relobj->symtab_index(lsi);
}
else
{
section_offset_type dummy;
Output_section* os = this->u1_.relobj->output_section(lsi, &dummy);
gold_assert(os != NULL);
if (dynamic)
index = os->dynsym_index();
else
index = os->symtab_index();
}
}
break;
}
gold_assert(index != -1U);
return index;
}
// For a local section symbol, get the section offset of the input
// section within the output section.
template<bool dynamic, int size, bool big_endian>
section_offset_type
Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::
local_section_offset() const
{
const unsigned int lsi = this->local_sym_index_;
section_offset_type offset;
Output_section* os = this->u1_.relobj->output_section(lsi, &offset);
gold_assert(os != NULL);
return offset;
}
// Write out the offset and info fields of a Rel or Rela relocation
// entry.
@ -825,8 +918,10 @@ Output_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>::write(
elfcpp::Rela_write<size, big_endian> orel(pov);
this->rel_.write_rel(&orel);
Addend addend = this->addend_;
if (rel_.is_relative())
addend += rel_.symbol_value();
if (this->rel_.is_relative())
addend += this->rel_.symbol_value();
if (this->rel_.is_local_section_symbol())
addend += this->rel_.local_section_offset();
orel.put_r_addend(addend);
}

View File

@ -767,9 +767,9 @@ class Output_data_strtab : public Output_section_data
// or elfcpp::SHT_RELA, and also on whether this is a dynamic
// relocation or an ordinary relocation.
// A relocation can be against a global symbol, a local symbol, an
// output section, or the undefined symbol at index 0. We represent
// the latter by using a NULL global symbol.
// A relocation can be against a global symbol, a local symbol, a
// local section symbol, an output section, or the undefined symbol at
// index 0. We represent the latter by using a NULL global symbol.
template<int sh_type, bool dynamic, int size, bool big_endian>
class Output_reloc;
@ -786,6 +786,11 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
: local_sym_index_(INVALID_CODE)
{ }
// We have a bunch of different constructors. They come in pairs
// depending on how the address of the relocation is specified. It
// can either be an offset in an Output_data or an offset in an
// input section.
// A reloc against a global symbol.
Output_reloc(Symbol* gsym, unsigned int type, Output_data* od,
@ -794,15 +799,17 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
Output_reloc(Symbol* gsym, unsigned int type, Relobj* relobj,
unsigned int shndx, Address address, bool is_relative);
// A reloc against a local symbol.
// A reloc against a local symbol or local section symbol.
Output_reloc(Sized_relobj<size, big_endian>* relobj,
unsigned int local_sym_index, unsigned int type,
Output_data* od, Address address, bool is_relative);
Output_data* od, Address address, bool is_relative,
bool is_section_symbol);
Output_reloc(Sized_relobj<size, big_endian>* relobj,
unsigned int local_sym_index, unsigned int type,
unsigned int shndx, Address address, bool is_relative);
unsigned int shndx, Address address, bool is_relative,
bool is_section_symbol);
// A reloc against the STT_SECTION symbol of an output section.
@ -817,6 +824,21 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
is_relative() const
{ return this->is_relative_; }
// Return whether this is against a local section symbol.
bool
is_local_section_symbol() const
{
return (this->local_sym_index_ != GSYM_CODE
&& this->local_sym_index_ != SECTION_CODE
&& this->local_sym_index_ != INVALID_CODE
&& this->is_section_symbol_);
}
// For a local section symbol, return the offset of the input
// section within the output section.
section_offset_type
local_section_offset() const;
// Get the value of the symbol referred to by a Rel relocation.
Address
@ -831,8 +853,11 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
void write_rel(Write_rel*) const;
private:
// Return the symbol index. We can't do a double template
// specialization, so we do a secondary template here.
// Record that we need a dynamic symbol index.
void
set_needs_dynsym_index();
// Return the symbol index.
unsigned int
get_symbol_index() const;
@ -849,36 +874,45 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
union
{
// For a local symbol, the object. We will never generate a
// relocation against a local symbol in a dynamic object; that
// doesn't make sense. And our callers will always be
// templatized, so we use Sized_relobj here.
// For a local symbol or local section symbol
// (this->local_sym_index_ >= 0), the object. We will never
// generate a relocation against a local symbol in a dynamic
// object; that doesn't make sense. And our callers will always
// be templatized, so we use Sized_relobj here.
Sized_relobj<size, big_endian>* relobj;
// For a global symbol, the symbol. If this is NULL, it indicates
// a relocation against the undefined 0 symbol.
// For a global symbol (this->local_sym_index_ == GSYM_CODE, the
// symbol. If this is NULL, it indicates a relocation against the
// undefined 0 symbol.
Symbol* gsym;
// For a relocation against an output section, the output section.
// For a relocation against an output section
// (this->local_sym_index_ == SECTION_CODE), the output section.
Output_section* os;
} u1_;
union
{
// If shndx_ is not INVALID CODE, the object which holds the input
// section being used to specify the reloc address.
// If this->shndx_ is not INVALID CODE, the object which holds the
// input section being used to specify the reloc address.
Relobj* relobj;
// If shndx_ is INVALID_CODE, the output data being used to
// If this->shndx_ is INVALID_CODE, the output data being used to
// specify the reloc address. This may be NULL if the reloc
// address is absolute.
Output_data* od;
} u2_;
// The address offset within the input section or the Output_data.
Address address_;
// For a local symbol, the local symbol index. This is GSYM_CODE
// for a global symbol, or INVALID_CODE for an uninitialized value.
// This is GSYM_CODE for a global symbol, or SECTION_CODE for a
// relocation against an output section, or INVALID_CODE for an
// uninitialized value. Otherwise, for a local symbol
// (this->is_section_symbol_ is false), the local symbol index. For
// a local section symbol (this->is_section_symbol_ is true), the
// section index in the input file.
unsigned int local_sym_index_;
// The reloc type--a processor specific code.
unsigned int type_ : 31;
unsigned int type_ : 30;
// True if the relocation is a RELATIVE relocation.
bool is_relative_ : 1;
// True if the relocation is against a section symbol.
bool is_section_symbol_ : 1;
// If the reloc address is an input section in an object, the
// section index. This is INVALID_CODE if the reloc address is
// specified in some other way.
@ -918,16 +952,18 @@ class Output_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
Output_reloc(Sized_relobj<size, big_endian>* relobj,
unsigned int local_sym_index, unsigned int type,
Output_data* od, Address address,
Addend addend, bool is_relative)
: rel_(relobj, local_sym_index, type, od, address, is_relative),
Addend addend, bool is_relative, bool is_section_symbol)
: rel_(relobj, local_sym_index, type, od, address, is_relative,
is_section_symbol),
addend_(addend)
{ }
Output_reloc(Sized_relobj<size, big_endian>* relobj,
unsigned int local_sym_index, unsigned int type,
unsigned int shndx, Address address,
Addend addend, bool is_relative)
: rel_(relobj, local_sym_index, type, shndx, address, is_relative),
Addend addend, bool is_relative, bool is_section_symbol)
: rel_(relobj, local_sym_index, type, shndx, address, is_relative,
is_section_symbol),
addend_(addend)
{ }
@ -1045,8 +1081,10 @@ class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
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)); }
{
this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
true));
}
// Add a reloc against a local symbol.
@ -1054,15 +1092,19 @@ class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
add_local(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, false)); }
{
this->add(od, Output_reloc_type(relobj, local_sym_index, type, od,
address, false, false));
}
void
add_local(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, false)); }
{
this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
address, false, false));
}
// Add a RELATIVE reloc against a local symbol.
@ -1070,15 +1112,41 @@ class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
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)); }
{
this->add(od, Output_reloc_type(relobj, local_sym_index, type, od,
address, true, false));
}
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)); }
{
this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
address, true, false));
}
// Add a reloc against a local section symbol. This will be
// converted into a reloc against the STT_SECTION symbol of the
// output section.
void
add_local_section(Sized_relobj<size, big_endian>* relobj,
unsigned int input_shndx, unsigned int type,
Output_data* od, Address address)
{
this->add(od, Output_reloc_type(relobj, input_shndx, type, od,
address, false, true));
}
void
add_local_section(Sized_relobj<size, big_endian>* relobj,
unsigned int input_shndx, unsigned int type,
Output_data* od, unsigned int shndx, Address address)
{
this->add(od, Output_reloc_type(relobj, input_shndx, type, shndx,
address, false, true));
}
// A reloc against the STT_SECTION symbol of an output section.
// OS is the Output_section that the relocation refers to; OD is
@ -1154,7 +1222,7 @@ class Output_data_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
Output_data* od, Address address, Addend addend)
{
this->add(od, Output_reloc_type(relobj, local_sym_index, type, od, address,
addend, false));
addend, false, false));
}
void
@ -1164,7 +1232,7 @@ class Output_data_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
Addend addend)
{
this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
address, addend, false));
address, addend, false, false));
}
// Add a RELATIVE reloc against a local symbol.
@ -1175,7 +1243,7 @@ class Output_data_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
Output_data* od, Address address, Addend addend)
{
this->add(od, Output_reloc_type(relobj, local_sym_index, type, od, address,
addend, true));
addend, true, false));
}
void
@ -1185,7 +1253,30 @@ class Output_data_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
Addend addend)
{
this->add(od, Output_reloc_type(relobj, local_sym_index, type, shndx,
address, addend, true));
address, addend, true, false));
}
// Add a reloc against a local section symbol. This will be
// converted into a reloc against the STT_SECTION symbol of the
// output section.
void
add_local_section(Sized_relobj<size, big_endian>* relobj,
unsigned int input_shndx, unsigned int type,
Output_data* od, Address address, Addend addend)
{
this->add(od, Output_reloc_type(relobj, input_shndx, type, od, address,
addend, false, true));
}
void
add_local_section(Sized_relobj<size, big_endian>* relobj,
unsigned int input_shndx, unsigned int type,
Output_data* od, unsigned int shndx, Address address,
Addend addend)
{
this->add(od, Output_reloc_type(relobj, input_shndx, type, shndx,
address, addend, false, true));
}
// A reloc against the STT_SECTION symbol of an output section.

View File

@ -828,10 +828,10 @@ Target_x86_64::Scan::local(const General_options&,
case elfcpp::R_X86_64_64:
// If building a shared library (or a position-independent
// executable), we need to create a dynamic relocation for
// this location. The relocation applied at link time will
// apply the link-time value, so we flag the location with
// an R_386_RELATIVE relocation so the dynamic loader can
// executable), we need to create a dynamic relocation for this
// location. The relocation applied at link time will apply the
// link-time value, so we flag the location with an
// R_X86_64_RELATIVE relocation so the dynamic loader can
// relocate it easily.
if (parameters->output_is_position_independent())
{
@ -850,19 +850,28 @@ Target_x86_64::Scan::local(const General_options&,
case elfcpp::R_X86_64_16:
case elfcpp::R_X86_64_8:
// If building a shared library (or a position-independent
// executable), we need to create a dynamic relocation for
// this location. The relocation applied at link time will
// apply the link-time value, so we flag the location with
// an R_386_RELATIVE relocation so the dynamic loader can
// relocate it easily.
// executable), we need to create a dynamic relocation for this
// location. We can't use an R_X86_64_RELATIVE relocation
// because that is always a 64-bit relocation.
if (parameters->output_is_position_independent())
{
Reloc_section* rela_dyn = target->rela_dyn_section(layout);
if (lsym.get_st_type() != elfcpp::STT_SECTION)
{
unsigned int r_sym = elfcpp::elf_r_sym<64>(reloc.get_r_info());
rela_dyn->add_local(object, r_sym, r_type, output_section,
data_shndx, reloc.get_r_offset(),
reloc.get_r_addend());
}
else
{
gold_assert(lsym.get_st_value() == 0);
rela_dyn->add_local_section(object, lsym.get_st_shndx(),
r_type, output_section,
data_shndx, reloc.get_r_offset(),
reloc.get_r_addend());
}
}
break;
case elfcpp::R_X86_64_PC64:
@ -909,8 +918,12 @@ Target_x86_64::Scan::local(const General_options&,
object->local_got_offset(r_sym),
0);
else
{
gold_assert(lsym.get_st_type() != elfcpp::STT_SECTION);
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);
}
}
}
// For GOTPLT64, we'd normally want a PLT section, but since