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>
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.
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>
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.
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>
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)
- os->set_needs_dynsym_index();
+ 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.
break;
default:
- if (dynamic)
- index = this->u1_.relobj->dynsym_index(this->local_sym_index_);
- else
- index = this->u1_.relobj->symtab_index(this->local_sym_index_);
+ {
+ const unsigned int lsi = this->local_sym_index_;
+ if (!this->is_section_symbol_)
+ {
+ if (dynamic)
+ index = this->u1_.relobj->dynsym_index(lsi);
+ else
+ 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.
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);
}
// 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;
: 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,
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.
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
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;
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.
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)
{ }
class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
: public Output_data_reloc_base<elfcpp::SHT_REL, dynamic, size, big_endian>
{
- private:
+ private:
typedef Output_data_reloc_base<elfcpp::SHT_REL, dynamic, size,
big_endian> Base;
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.
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.
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
class Output_data_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
: public Output_data_reloc_base<elfcpp::SHT_RELA, dynamic, size, big_endian>
{
- private:
+ private:
typedef Output_data_reloc_base<elfcpp::SHT_RELA, dynamic, size,
big_endian> Base;
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
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.
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
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.