aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@google.com>2008-02-12 00:28:48 +0000
committerIan Lance Taylor <iant@google.com>2008-02-12 00:28:48 +0000
commitdceae3c154edcb9aada9f94452a72548a82914f5 (patch)
treeb9fb771a92a28b7047bdea1b9e2104e8d6b82f73
parent709d67f15ab46ff1d18da0e2c2c7dcea140155a5 (diff)
downloadbinutils-dceae3c154edcb9aada9f94452a72548a82914f5.zip
binutils-dceae3c154edcb9aada9f94452a72548a82914f5.tar.gz
binutils-dceae3c154edcb9aada9f94452a72548a82914f5.tar.bz2
Support dynamic relocations against local section symbols.
-rw-r--r--gold/i386.cc17
-rw-r--r--gold/object.cc2
-rw-r--r--gold/object.h9
-rw-r--r--gold/output.cc143
-rw-r--r--gold/output.h173
-rw-r--r--gold/x86_64.cc43
6 files changed, 302 insertions, 85 deletions
diff --git a/gold/i386.cc b/gold/i386.cc
index d6e42f4..2d8efdd 100644
--- a/gold/i386.cc
+++ b/gold/i386.cc
@@ -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);
- 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());
+ 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());
+ }
+ 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
diff --git a/gold/object.cc b/gold/object.cc
index 1adb851..3db6f85 100644
--- a/gold/object.cc
+++ b/gold/object.cc
@@ -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;
}
diff --git a/gold/object.h b/gold/object.h
index 36a2e1f..4011bdc 100644
--- a/gold/object.h
+++ b/gold/object.h
@@ -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
diff --git a/gold/output.cc b/gold/output.cc
index 8aca916..107ed09 100644
--- a/gold/output.cc
+++ b/gold/output.cc
@@ -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)
- 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.
@@ -744,16 +806,47 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::get_symbol_index()
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.
@@ -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);
}
diff --git a/gold/output.h b/gold/output.h
index fbfdb25..8f7a564 100644
--- a/gold/output.h
+++ b/gold/output.h
@@ -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)
{ }
@@ -1010,7 +1046,7 @@ template<bool dynamic, int size, bool big_endian>
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;
@@ -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
@@ -1101,7 +1169,7 @@ template<bool dynamic, int size, bool big_endian>
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;
@@ -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.
diff --git a/gold/x86_64.cc b/gold/x86_64.cc
index 54357fd..d5869dc 100644
--- a/gold/x86_64.cc
+++ b/gold/x86_64.cc
@@ -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,18 +850,27 @@ 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);
- 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());
+ 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;
@@ -909,8 +918,12 @@ Target_x86_64::Scan::local(const General_options&,
object->local_got_offset(r_sym),
0);
else
- rela_dyn->add_local(object, r_sym, r_type,
- got, object->local_got_offset(r_sym), 0);
+ {
+ 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);
+ }
}
}
// For GOTPLT64, we'd normally want a PLT section, but since