aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@google.com>2007-09-23 05:31:48 +0000
committerIan Lance Taylor <iant@google.com>2007-09-23 05:31:48 +0000
commitab5c9e90a6d088f6b09bdc8f6bee09c911789df6 (patch)
tree315b4833fd2030948138845c5f58b05f252dc918
parentcb615bc189241f02996054391ade06ba06147147 (diff)
downloadfsf-binutils-gdb-ab5c9e90a6d088f6b09bdc8f6bee09c911789df6.zip
fsf-binutils-gdb-ab5c9e90a6d088f6b09bdc8f6bee09c911789df6.tar.gz
fsf-binutils-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.cc30
-rw-r--r--gold/symtab.cc24
-rw-r--r--gold/symtab.h22
-rw-r--r--gold/target.h12
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