diff options
author | Ian Lance Taylor <iant@google.com> | 2008-02-12 00:28:48 +0000 |
---|---|---|
committer | Ian Lance Taylor <iant@google.com> | 2008-02-12 00:28:48 +0000 |
commit | dceae3c154edcb9aada9f94452a72548a82914f5 (patch) | |
tree | b9fb771a92a28b7047bdea1b9e2104e8d6b82f73 /gold/output.cc | |
parent | 709d67f15ab46ff1d18da0e2c2c7dcea140155a5 (diff) | |
download | binutils-dceae3c154edcb9aada9f94452a72548a82914f5.zip binutils-dceae3c154edcb9aada9f94452a72548a82914f5.tar.gz binutils-dceae3c154edcb9aada9f94452a72548a82914f5.tar.bz2 |
Support dynamic relocations against local section symbols.
Diffstat (limited to 'gold/output.cc')
-rw-r--r-- | gold/output.cc | 143 |
1 files changed, 119 insertions, 24 deletions
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); } |