diff options
author | Ian Lance Taylor <iant@google.com> | 2007-09-23 05:31:48 +0000 |
---|---|---|
committer | Ian Lance Taylor <iant@google.com> | 2007-09-23 05:31:48 +0000 |
commit | ab5c9e90a6d088f6b09bdc8f6bee09c911789df6 (patch) | |
tree | 315b4833fd2030948138845c5f58b05f252dc918 | |
parent | cb615bc189241f02996054391ade06ba06147147 (diff) | |
download | gdb-ab5c9e90a6d088f6b09bdc8f6bee09c911789df6.zip gdb-ab5c9e90a6d088f6b09bdc8f6bee09c911789df6.tar.gz gdb-ab5c9e90a6d088f6b09bdc8f6bee09c911789df6.tar.bz2 |
Use special value when we refer a function symbol in some way other
than calling it.
-rw-r--r-- | gold/i386.cc | 30 | ||||
-rw-r--r-- | gold/symtab.cc | 24 | ||||
-rw-r--r-- | gold/symtab.h | 22 | ||||
-rw-r--r-- | gold/target.h | 12 |
4 files changed, 76 insertions, 12 deletions
diff --git a/gold/i386.cc b/gold/i386.cc index 00ac288..54c388b 100644 --- a/gold/i386.cc +++ b/gold/i386.cc @@ -74,6 +74,11 @@ class Target_i386 : public Sized_target<32, false> void do_finalize_sections(Layout*); + // Return the value to use for a dynamic which requires special + // treatment. + uint64_t + do_dynsym_value(const Symbol*) const; + // Relocate a section. void relocate_section(const Relocate_info<32, false>*, @@ -844,7 +849,18 @@ Target_i386::Scan::global(const General_options& options, // function, we make a PLT entry. Otherwise we need to // either generate a COPY reloc or copy this reloc. if (gsym->type() == elfcpp::STT_FUNC) - target->make_plt_entry(symtab, layout, gsym); + { + target->make_plt_entry(symtab, layout, gsym); + + // If this is not a PC relative reference, then we may + // be taking the address of the function. In that case + // we need to set the entry in the dynamic symbol table + // to the address of the PLT entry. + if (r_type != elfcpp::R_386_PC32 + && r_type != elfcpp::R_386_PC16 + && r_type != elfcpp::R_386_PC8) + gsym->set_needs_dynsym_value(); + } else target->copy_reloc(&options, symtab, layout, object, data_shndx, gsym, reloc); @@ -1507,6 +1523,18 @@ Target_i386::relocate_section(const Relocate_info<32, false>* relinfo, view_size); } +// Return the value to use for a dynamic which requires special +// treatment. This is how we support equality comparisons of function +// pointers across shared library boundaries, as described in the +// processor specific ABI supplement. + +uint64_t +Target_i386::do_dynsym_value(const Symbol* gsym) const +{ + gold_assert(gsym->is_from_dynobj() && gsym->has_plt_offset()); + return this->plt_section()->address() + gsym->plt_offset(); +} + // Return a string used to fill a code section with nops to take up // the specified length. diff --git a/gold/symtab.cc b/gold/symtab.cc index 2260aca..8cd55cd 100644 --- a/gold/symtab.cc +++ b/gold/symtab.cc @@ -1307,7 +1307,7 @@ Symbol_table::write_globals(const Target* target, const Stringpool* sympool, template<int size, bool big_endian> void -Symbol_table::sized_write_globals(const Target*, +Symbol_table::sized_write_globals(const Target* target, const Stringpool* sympool, const Stringpool* dynpool, Output_file* of) const @@ -1359,6 +1359,7 @@ Symbol_table::sized_write_globals(const Target*, } unsigned int shndx; + typename elfcpp::Elf_types<32>::Elf_Addr value = sym->value(); switch (sym->source()) { case Symbol::FROM_OBJECT: @@ -1377,7 +1378,8 @@ Symbol_table::sized_write_globals(const Target*, Object* symobj = sym->object(); if (symobj->is_dynamic()) { - // FIXME. + if (sym->needs_dynsym_value()) + value = target->dynsym_value(sym); shndx = elfcpp::SHN_UNDEF; } else if (in_shndx == elfcpp::SHN_UNDEF @@ -1413,7 +1415,7 @@ Symbol_table::sized_write_globals(const Target*, if (sym_index != -1U) { this->sized_write_symbol SELECT_SIZE_ENDIAN_NAME(size, big_endian) ( - sym, shndx, sympool, ps + sym, sym->value(), shndx, sympool, ps SELECT_SIZE_ENDIAN(size, big_endian)); ps += sym_size; } @@ -1424,7 +1426,7 @@ Symbol_table::sized_write_globals(const Target*, gold_assert(dynsym_index < dynamic_count); unsigned char* pd = dynamic_view + (dynsym_index * sym_size); this->sized_write_symbol SELECT_SIZE_ENDIAN_NAME(size, big_endian) ( - sym, shndx, dynpool, pd + sym, value, shndx, dynpool, pd SELECT_SIZE_ENDIAN(size, big_endian)); } } @@ -1441,15 +1443,17 @@ Symbol_table::sized_write_globals(const Target*, template<int size, bool big_endian> void -Symbol_table::sized_write_symbol(Sized_symbol<size>* sym, - unsigned int shndx, - const Stringpool* pool, - unsigned char* p - ACCEPT_SIZE_ENDIAN) const +Symbol_table::sized_write_symbol( + Sized_symbol<size>* sym, + typename elfcpp::Elf_types<size>::Elf_Addr value, + unsigned int shndx, + const Stringpool* pool, + unsigned char* p + ACCEPT_SIZE_ENDIAN) const { elfcpp::Sym_write<size, big_endian> osym(p); osym.put_st_name(pool->get_offset(sym->name())); - osym.put_st_value(sym->value()); + osym.put_st_value(value); osym.put_st_size(sym->symsize()); osym.put_st_info(elfcpp::elf_st_info(sym->binding(), sym->type())); osym.put_st_other(elfcpp::elf_st_other(sym->visibility(), sym->nonvis())); diff --git a/gold/symtab.h b/gold/symtab.h index 6420638..36414bc 100644 --- a/gold/symtab.h +++ b/gold/symtab.h @@ -323,6 +323,21 @@ class Symbol this->plt_offset_ = plt_offset; } + // Return whether this dynamic symbol needs a special value in the + // dynamic symbol table. + bool + needs_dynsym_value() const + { return this->needs_dynsym_value_; } + + // Set that this dynamic symbol needs a special value in the dynamic + // symbol table. + void + set_needs_dynsym_value() + { + gold_assert(this->object()->is_dynamic()); + this->needs_dynsym_value_ = true; + } + // Return true if the final value of this symbol is known at link // time. bool @@ -528,6 +543,9 @@ class Symbol bool has_got_offset_ : 1; // True if the symbol has an entry in the PLT section. bool has_plt_offset_ : 1; + // True if this is a dynamic symbol which needs a special value in + // the dynamic symbol table. + bool needs_dynsym_value_ : 1; // True if there is a warning for this symbol. bool has_warning_ : 1; }; @@ -1003,7 +1021,9 @@ class Symbol_table // Write out a symbol to P. template<int size, bool big_endian> void - sized_write_symbol(Sized_symbol<size>*, unsigned int shndx, + sized_write_symbol(Sized_symbol<size>*, + typename elfcpp::Elf_types<size>::Elf_Addr value, + unsigned int shndx, const Stringpool*, unsigned char* p ACCEPT_SIZE_ENDIAN) const; diff --git a/gold/target.h b/gold/target.h index 32ad143..31037ef 100644 --- a/gold/target.h +++ b/gold/target.h @@ -114,6 +114,13 @@ class Target finalize_sections(Layout* layout) { return this->do_finalize_sections(layout); } + // Return the value to use for a global symbol which needs a special + // value in the dynamic symbol table. This will only be called if + // the backend first calls symbol->set_needs_dynsym_value(). + uint64_t + dynsym_value(const Symbol* sym) const + { return this->do_dynsym_value(sym); } + // Return a string to use to fill out a code section. This is // basically one or more NOPS which must fill out the specified // length in bytes. @@ -158,6 +165,11 @@ class Target do_finalize_sections(Layout*) { } + // Virtual function which may be implemented by the child class. + virtual uint64_t + do_dynsym_value(const Symbol*) const + { gold_unreachable(); } + // Virtual function which must be implemented by the child class if // needed. virtual std::string |