From dceae3c154edcb9aada9f94452a72548a82914f5 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 12 Feb 2008 00:28:48 +0000 Subject: [PATCH] Support dynamic relocations against local section symbols. --- gold/i386.cc | 17 ++++- gold/object.cc | 2 + gold/object.h | 9 ++- gold/output.cc | 143 +++++++++++++++++++++++++++++++++------- gold/output.h | 173 +++++++++++++++++++++++++++++++++++++------------ gold/x86_64.cc | 43 +++++++----- 6 files changed, 302 insertions(+), 85 deletions(-) diff --git a/gold/i386.cc b/gold/i386.cc index d6e42f4650..2d8efdd5ec 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 1adb851ba1..3db6f851b9 100644 --- a/gold/object.cc +++ b/gold/object.cc @@ -884,12 +884,14 @@ Sized_relobj::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 36a2e1f495..4011bdcf22 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 8aca916be0..107ed09c4b 100644 --- a/gold/output.cc +++ b/gold/output.cc @@ -608,12 +608,14 @@ Output_reloc::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 @@ -625,13 +627,15 @@ Output_reloc::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::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 @@ -662,17 +670,21 @@ Output_reloc::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::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 @@ -700,13 +716,59 @@ Output_reloc::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 +void +Output_reloc:: +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::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 +section_offset_type +Output_reloc:: + 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::write( elfcpp::Rela_write 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 fbfdb25626..8f7a564475 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 class Output_reloc; @@ -786,6 +786,11 @@ 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, @@ -794,15 +799,17 @@ class Output_reloc 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* 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* 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 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 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 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* 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 Output_reloc(Sized_relobj* 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* 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 class Output_data_reloc : public Output_data_reloc_base { - private: + private: typedef Output_data_reloc_base Base; @@ -1045,8 +1081,10 @@ class Output_data_reloc 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 add_local(Sized_relobj* 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* 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 add_local_relative(Sized_relobj* 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* 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* 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* 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 class Output_data_reloc : public Output_data_reloc_base { - private: + private: typedef Output_data_reloc_base Base; @@ -1154,7 +1222,7 @@ class Output_data_reloc 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 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 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 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* 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* 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 54357fdaeb..d5869dc5f6 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 -- 2.34.1