diff options
author | Ian Lance Taylor <iant@google.com> | 2007-12-07 19:32:59 +0000 |
---|---|---|
committer | Ian Lance Taylor <iant@google.com> | 2007-12-07 19:32:59 +0000 |
commit | e8c846c359fda086b5e550fc795cc1c05b6ee003 (patch) | |
tree | a7efff24a88e4874d11de980263ed408bd5d7a97 /gold/output.cc | |
parent | c68cf8ad105b1605718ea48e5f0f118b35be5654 (diff) | |
download | gdb-e8c846c359fda086b5e550fc795cc1c05b6ee003.zip gdb-e8c846c359fda086b5e550fc795cc1c05b6ee003.tar.gz gdb-e8c846c359fda086b5e550fc795cc1c05b6ee003.tar.bz2 |
From Cary Coutant: Fix handling of RELATIVE RELA relocs.
Diffstat (limited to 'gold/output.cc')
-rw-r--r-- | gold/output.cc | 85 |
1 files changed, 51 insertions, 34 deletions
diff --git a/gold/output.cc b/gold/output.cc index 7fd901c..922a9e5 100644 --- a/gold/output.cc +++ b/gold/output.cc @@ -512,13 +512,14 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc( Symbol* gsym, unsigned int type, Output_data* od, - Address address) + Address address, + bool is_relative) : address_(address), local_sym_index_(GSYM_CODE), type_(type), - shndx_(INVALID_CODE) + is_relative_(is_relative), shndx_(INVALID_CODE) { this->u1_.gsym = gsym; this->u2_.od = od; - if (dynamic) + if (dynamic && !is_relative) gsym->set_needs_dynsym_entry(); } @@ -528,14 +529,15 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc( unsigned int type, Relobj* relobj, unsigned int shndx, - Address address) + Address address, + bool is_relative) : address_(address), local_sym_index_(GSYM_CODE), type_(type), - shndx_(shndx) + is_relative_(is_relative), shndx_(shndx) { gold_assert(shndx != INVALID_CODE); this->u1_.gsym = gsym; this->u2_.relobj = relobj; - if (dynamic) + if (dynamic && !is_relative) gsym->set_needs_dynsym_entry(); } @@ -547,15 +549,16 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc( unsigned int local_sym_index, unsigned int type, Output_data* od, - Address address) + Address address, + bool is_relative) : address_(address), local_sym_index_(local_sym_index), type_(type), - shndx_(INVALID_CODE) + is_relative_(is_relative), shndx_(INVALID_CODE) { gold_assert(local_sym_index != GSYM_CODE && local_sym_index != INVALID_CODE); this->u1_.relobj = relobj; this->u2_.od = od; - if (dynamic && local_sym_index > 0) + if (dynamic && !is_relative) relobj->set_needs_output_dynsym_entry(local_sym_index); } @@ -565,16 +568,17 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc( unsigned int local_sym_index, unsigned int type, unsigned int shndx, - Address address) + Address address, + bool is_relative) : address_(address), local_sym_index_(local_sym_index), type_(type), - shndx_(shndx) + is_relative_(is_relative), shndx_(shndx) { gold_assert(local_sym_index != GSYM_CODE && local_sym_index != INVALID_CODE); gold_assert(shndx != INVALID_CODE); this->u1_.relobj = relobj; this->u2_.relobj = relobj; - if (dynamic && local_sym_index > 0) + if (dynamic && !is_relative) relobj->set_needs_output_dynsym_entry(local_sym_index); } @@ -587,7 +591,7 @@ 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), - shndx_(INVALID_CODE) + is_relative_(false), shndx_(INVALID_CODE) { this->u1_.os = os; this->u2_.od = od; @@ -603,7 +607,7 @@ 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), - shndx_(shndx) + is_relative_(false), shndx_(shndx) { gold_assert(shndx != INVALID_CODE); this->u1_.os = os; @@ -685,8 +689,8 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::write_rel( else if (this->u2_.od != NULL) address += this->u2_.od->address(); wr->put_r_offset(address); - wr->put_r_info(elfcpp::elf_r_info<size>(this->get_symbol_index(), - this->type_)); + unsigned int sym_index = this->is_relative_ ? 0 : this->get_symbol_index(); + wr->put_r_info(elfcpp::elf_r_info<size>(sym_index, this->type_)); } // Write out a Rel relocation. @@ -700,6 +704,24 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::write( this->write_rel(&orel); } +// Get the value of the symbol referred to by a Rel relocation. + +template<bool dynamic, int size, bool big_endian> +typename elfcpp::Elf_types<size>::Elf_Addr +Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::symbol_value() const +{ + if (this->local_sym_index_ == GSYM_CODE) + { + const Sized_symbol<size>* sym; + sym = static_cast<const Sized_symbol<size>*>(this->u1_.gsym); + return sym->value(); + } + gold_assert(this->local_sym_index_ != SECTION_CODE + && this->local_sym_index_ != INVALID_CODE); + const Sized_relobj<size, big_endian>* relobj = this->u1_.relobj; + return relobj->local_symbol_value(this->local_sym_index_); +} + // Write out a Rela relocation. template<bool dynamic, int size, bool big_endian> @@ -709,7 +731,10 @@ Output_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>::write( { elfcpp::Rela_write<size, big_endian> orel(pov); this->rel_.write_rel(&orel); - orel.put_r_addend(this->addend_); + Addend addend = this->addend_; + if (rel_.is_relative()) + addend += rel_.symbol_value(); + orel.put_r_addend(addend); } // Output_data_reloc_base methods. @@ -775,24 +800,16 @@ Output_data_got<size, big_endian>::Got_entry::write(unsigned char* pov) const { case GSYM_CODE: { + // If the symbol is resolved locally, we need to write out the + // link-time value, which will be relocated dynamically by a + // RELATIVE relocation. Symbol* gsym = this->u_.gsym; - - // If the symbol is resolved locally, we need to write out its - // value. Otherwise we just write zero. The target code is - // responsible for creating a relocation entry to fill in the - // value at runtime. For non-preemptible symbols in a shared - // library, the target will need to record whether or not the - // value should be written (e.g., it may use a RELATIVE - // relocation type). - if (gsym->final_value_is_known() || gsym->needs_value_in_got()) - { - Sized_symbol<size>* sgsym; - // This cast is a bit ugly. We don't want to put a - // virtual method in Symbol, because we want Symbol to be - // as small as possible. - sgsym = static_cast<Sized_symbol<size>*>(gsym); - val = sgsym->value(); - } + Sized_symbol<size>* sgsym; + // This cast is a bit ugly. We don't want to put a + // virtual method in Symbol, because we want Symbol to be + // as small as possible. + sgsym = static_cast<Sized_symbol<size>*>(gsym); + val = sgsym->value(); } break; |