diff options
-rw-r--r-- | gold/ChangeLog | 20 | ||||
-rw-r--r-- | gold/resolve.cc | 57 | ||||
-rw-r--r-- | gold/symtab.cc | 12 | ||||
-rw-r--r-- | gold/symtab.h | 26 | ||||
-rw-r--r-- | gold/testsuite/weak_undef_file1.cc | 10 | ||||
-rw-r--r-- | gold/testsuite/weak_undef_file2.cc | 4 | ||||
-rw-r--r-- | gold/testsuite/weak_undef_test.cc | 17 |
7 files changed, 127 insertions, 19 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog index 188cb32..69e420f 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,3 +1,23 @@ +2010-07-08 Cary Coutant <ccoutant@google.com> + + * resolve.cc (Symbol_table::resolve): Remember whether undef was + weak when resolving to a dynamic def. + (Symbol_table::should_override): Add adjust_dyndef flag; set it + for weak undef/dynamic def cases. Adjust callers. + * symtab.cc (Symbol::init_fields): Initialize undef_binding_set_ and + undef_binding_weak_. + (Symbol_table::sized_write_globals): Adjust symbol binding. + (Symbol_table::sized_write_symbol): Add binding parameter. + * symtab.h (Symbol::set_undef_binding): New method. + (Symbol::is_undef_binding_weak): New method. + (Symbol::undef_binding_set_, Symbol::undef_binding_weak_): New members. + (Symbol_table::should_override): Add new parameter. + (Symbol_table::sized_write_symbol): Add new parameter. + + * testsuite/weak_undef_file1.cc: Add new test case. + * testsuite/weak_undef_file2.cc: Fix header comment. + * testsuite/weak_undef_test.cc: Add new test case. + 2010-06-29 Doug Kwan <dougkwan@google.com> * arm-reloc-property.cc (Arm_reloc_property::Arm_reloc_property): diff --git a/gold/resolve.cc b/gold/resolve.cc index 8b1c321..af3d489 100644 --- a/gold/resolve.cc +++ b/gold/resolve.cc @@ -335,18 +335,33 @@ Symbol_table::resolve(Sized_symbol<size>* to, sym.get_st_type()); bool adjust_common_sizes; + bool adjust_dyndef; typename Sized_symbol<size>::Size_type tosize = to->symsize(); if (Symbol_table::should_override(to, frombits, OBJECT, object, - &adjust_common_sizes)) + &adjust_common_sizes, + &adjust_dyndef)) { + elfcpp::STB tobinding = to->binding(); this->override(to, sym, st_shndx, is_ordinary, object, version); if (adjust_common_sizes && tosize > to->symsize()) to->set_symsize(tosize); + if (adjust_dyndef) + { + // We are overriding an UNDEF or WEAK UNDEF with a DYN DEF. + // Remember which kind of UNDEF it was for future reference. + to->set_undef_binding(tobinding); + } } else { if (adjust_common_sizes && sym.get_st_size() > tosize) to->set_symsize(sym.get_st_size()); + if (adjust_dyndef) + { + // We are keeping a DYN DEF after seeing an UNDEF or WEAK UNDEF. + // Remember which kind of UNDEF it was. + to->set_undef_binding(sym.get_st_bind()); + } // The ELF ABI says that even for a reference to a symbol we // merge the visibility. to->override_visibility(sym.get_st_visibility()); @@ -381,9 +396,11 @@ Symbol_table::resolve(Sized_symbol<size>* to, bool Symbol_table::should_override(const Symbol* to, unsigned int frombits, Defined defined, Object* object, - bool* adjust_common_sizes) + bool* adjust_common_sizes, + bool* adjust_dyndef) { *adjust_common_sizes = false; + *adjust_dyndef = false; unsigned int tobits; if (to->source() == Symbol::IS_UNDEFINED) @@ -531,12 +548,17 @@ Symbol_table::should_override(const Symbol* to, unsigned int frombits, return false; case UNDEF * 16 + DYN_DEF: - case WEAK_UNDEF * 16 + DYN_DEF: case DYN_UNDEF * 16 + DYN_DEF: case DYN_WEAK_UNDEF * 16 + DYN_DEF: // Use a dynamic definition if we have a reference. return true; + case WEAK_UNDEF * 16 + DYN_DEF: + // When overriding a weak undef by a dynamic definition, + // we need to remember that the original undef was weak. + *adjust_dyndef = true; + return true; + case COMMON * 16 + DYN_DEF: case WEAK_COMMON * 16 + DYN_DEF: case DYN_COMMON * 16 + DYN_DEF: @@ -554,12 +576,17 @@ Symbol_table::should_override(const Symbol* to, unsigned int frombits, return false; case UNDEF * 16 + DYN_WEAK_DEF: - case WEAK_UNDEF * 16 + DYN_WEAK_DEF: case DYN_UNDEF * 16 + DYN_WEAK_DEF: case DYN_WEAK_UNDEF * 16 + DYN_WEAK_DEF: // Use a weak dynamic definition if we have a reference. return true; + case WEAK_UNDEF * 16 + DYN_WEAK_DEF: + // When overriding a weak undef by a dynamic definition, + // we need to remember that the original undef was weak. + *adjust_dyndef = true; + return true; + case COMMON * 16 + DYN_WEAK_DEF: case WEAK_COMMON * 16 + DYN_WEAK_DEF: case DYN_COMMON * 16 + DYN_WEAK_DEF: @@ -570,12 +597,16 @@ Symbol_table::should_override(const Symbol* to, unsigned int frombits, case DEF * 16 + UNDEF: case WEAK_DEF * 16 + UNDEF: - case DYN_DEF * 16 + UNDEF: - case DYN_WEAK_DEF * 16 + UNDEF: case UNDEF * 16 + UNDEF: // A new undefined reference tells us nothing. return false; + case DYN_DEF * 16 + UNDEF: + case DYN_WEAK_DEF * 16 + UNDEF: + // For a dynamic def, we need to remember which kind of undef we see. + *adjust_dyndef = true; + return false; + case WEAK_UNDEF * 16 + UNDEF: case DYN_UNDEF * 16 + UNDEF: case DYN_WEAK_UNDEF * 16 + UNDEF: @@ -591,8 +622,6 @@ Symbol_table::should_override(const Symbol* to, unsigned int frombits, case DEF * 16 + WEAK_UNDEF: case WEAK_DEF * 16 + WEAK_UNDEF: - case DYN_DEF * 16 + WEAK_UNDEF: - case DYN_WEAK_DEF * 16 + WEAK_UNDEF: case UNDEF * 16 + WEAK_UNDEF: case WEAK_UNDEF * 16 + WEAK_UNDEF: case DYN_UNDEF * 16 + WEAK_UNDEF: @@ -604,6 +633,12 @@ Symbol_table::should_override(const Symbol* to, unsigned int frombits, // A new weak undefined reference tells us nothing. return false; + case DYN_DEF * 16 + WEAK_UNDEF: + case DYN_WEAK_DEF * 16 + WEAK_UNDEF: + // For a dynamic def, we need to remember which kind of undef we see. + *adjust_dyndef = true; + return false; + case DEF * 16 + DYN_UNDEF: case WEAK_DEF * 16 + DYN_UNDEF: case DYN_DEF * 16 + DYN_UNDEF: @@ -811,10 +846,12 @@ bool Symbol_table::should_override_with_special(const Symbol* to, Defined defined) { bool adjust_common_sizes; + bool adjust_dyn_def; unsigned int frombits = global_flag | regular_flag | def_flag; bool ret = Symbol_table::should_override(to, frombits, defined, NULL, - &adjust_common_sizes); - gold_assert(!adjust_common_sizes); + &adjust_common_sizes, + &adjust_dyn_def); + gold_assert(!adjust_common_sizes && !adjust_dyn_def); return ret; } diff --git a/gold/symtab.cc b/gold/symtab.cc index c721ae4..a29e6ad 100644 --- a/gold/symtab.cc +++ b/gold/symtab.cc @@ -76,6 +76,8 @@ Symbol::init_fields(const char* name, const char* version, this->is_ordinary_shndx_ = false; this->in_real_elf_ = false; this->is_defined_in_discarded_section_ = false; + this->undef_binding_set_ = false; + this->undef_binding_weak_ = false; } // Return the demangled version of the symbol's name, but only @@ -2697,6 +2699,7 @@ Symbol_table::sized_write_globals(const Stringpool* sympool, unsigned int shndx; typename elfcpp::Elf_types<size>::Elf_Addr sym_value = sym->value(); typename elfcpp::Elf_types<size>::Elf_Addr dynsym_value = sym_value; + elfcpp::STB binding = sym->binding(); switch (sym->source()) { case Symbol::FROM_OBJECT: @@ -2720,6 +2723,8 @@ Symbol_table::sized_write_globals(const Stringpool* sympool, if (sym->needs_dynsym_value()) dynsym_value = target.dynsym_value(sym); shndx = elfcpp::SHN_UNDEF; + if (sym->is_undef_binding_weak()) + binding = elfcpp::STB_WEAK; } else if (symobj->pluginobj() != NULL) shndx = elfcpp::SHN_UNDEF; @@ -2800,7 +2805,7 @@ Symbol_table::sized_write_globals(const Stringpool* sympool, gold_assert(sym_index < output_count); unsigned char* ps = psyms + (sym_index * sym_size); this->sized_write_symbol<size, big_endian>(sym, sym_value, shndx, - sympool, ps); + binding, sympool, ps); } if (dynsym_index != -1U) @@ -2809,7 +2814,7 @@ Symbol_table::sized_write_globals(const Stringpool* sympool, gold_assert(dynsym_index < dynamic_count); unsigned char* pd = dynamic_view + (dynsym_index * sym_size); this->sized_write_symbol<size, big_endian>(sym, dynsym_value, shndx, - dynpool, pd); + binding, dynpool, pd); } } @@ -2827,6 +2832,7 @@ Symbol_table::sized_write_symbol( Sized_symbol<size>* sym, typename elfcpp::Elf_types<size>::Elf_Addr value, unsigned int shndx, + elfcpp::STB binding, const Stringpool* pool, unsigned char* p) const { @@ -2847,7 +2853,7 @@ Symbol_table::sized_write_symbol( if (sym->is_forced_local()) osym.put_st_info(elfcpp::elf_st_info(elfcpp::STB_LOCAL, type)); else - osym.put_st_info(elfcpp::elf_st_info(sym->binding(), type)); + osym.put_st_info(elfcpp::elf_st_info(binding, type)); osym.put_st_other(elfcpp::elf_st_other(sym->visibility(), sym->nonvis())); osym.put_st_shndx(shndx); } diff --git a/gold/symtab.h b/gold/symtab.h index 7d75e06..3058546 100644 --- a/gold/symtab.h +++ b/gold/symtab.h @@ -227,6 +227,23 @@ class Symbol void override_visibility(elfcpp::STV); + // Set whether the symbol was originally a weak undef or a regular undef + // when resolved by a dynamic def. + inline void + set_undef_binding(elfcpp::STB bind) + { + if (!this->undef_binding_set_ || this->undef_binding_weak_) + { + this->undef_binding_weak_ = bind == elfcpp::STB_WEAK; + this->undef_binding_set_ = true; + } + } + + // Return TRUE if a weak undef was resolved by a dynamic def. + inline bool + is_undef_binding_weak() const + { return this->undef_binding_weak_; } + // Return the non-visibility part of the st_other field. unsigned char nonvis() const @@ -949,6 +966,11 @@ class Symbol // True if this symbol is defined in a section which was discarded // (bit 31). bool is_defined_in_discarded_section_ : 1; + // True if UNDEF_BINDING_WEAK_ has been set (bit 32). + bool undef_binding_set_ : 1; + // True if this symbol was a weak undef resolved by a dynamic def + // (bit 33). + bool undef_binding_weak_ : 1; }; // The parts of a symbol which are size specific. Using a template @@ -1536,7 +1558,7 @@ class Symbol_table // Whether we should override a symbol, based on flags in // resolve.cc. static bool - should_override(const Symbol*, unsigned int, Defined, Object*, bool*); + should_override(const Symbol*, unsigned int, Defined, Object*, bool*, bool*); // Report a problem in symbol resolution. static void @@ -1667,7 +1689,7 @@ class Symbol_table void sized_write_symbol(Sized_symbol<size>*, typename elfcpp::Elf_types<size>::Elf_Addr value, - unsigned int shndx, + unsigned int shndx, elfcpp::STB, const Stringpool*, unsigned char* p) const; // Possibly warn about an undefined symbol from a dynamic object. diff --git a/gold/testsuite/weak_undef_file1.cc b/gold/testsuite/weak_undef_file1.cc index 743eea6..fd28870 100644 --- a/gold/testsuite/weak_undef_file1.cc +++ b/gold/testsuite/weak_undef_file1.cc @@ -1,6 +1,6 @@ // weak_undef_file1.cc -- test handling of weak undefined symbols for gold -// Copyright 2008 Free Software Foundation, Inc. +// Copyright 2008, 2010 Free Software Foundation, Inc. // Written by Cary Coutant <ccoutant@google.com>. // This file is part of gold. @@ -33,13 +33,19 @@ // so that we can detect whether the symbol was left for runtime // resolution. - #include <cstdio> #include "weak_undef.h" int is_such_symbol_ = 1; +// We also define a symbol that is not defined by the alternate +// library. The main program contains a weak reference to this +// symbol, and tests that the reference remains weak even after +// the definition was found at link time. + +int link_time_only = 1; + extern int v2 __attribute__ ((weak)); int *v3 = &v2; diff --git a/gold/testsuite/weak_undef_file2.cc b/gold/testsuite/weak_undef_file2.cc index 610c25e..33701b2 100644 --- a/gold/testsuite/weak_undef_file2.cc +++ b/gold/testsuite/weak_undef_file2.cc @@ -1,6 +1,6 @@ -// weak_undef_file1.cc -- test handling of weak undefined symbols for gold +// weak_undef_file2.cc -- test handling of weak undefined symbols for gold -// Copyright 2008 Free Software Foundation, Inc. +// Copyright 2008, 2010 Free Software Foundation, Inc. // Written by Cary Coutant <ccoutant@google.com>. // This file is part of gold. diff --git a/gold/testsuite/weak_undef_test.cc b/gold/testsuite/weak_undef_test.cc index 962b6bf..880d5cd 100644 --- a/gold/testsuite/weak_undef_test.cc +++ b/gold/testsuite/weak_undef_test.cc @@ -34,14 +34,24 @@ // so that we can detect whether the symbol was left for runtime // resolution. +// Similarly, this file will be linked with a shared library that +// does define a different symbol, and loaded with an alternate +// shared library that does not define that symbol. We check that +// the weak reference remains weak, and that it is resolved to +// zero at runtime. + #include <cstdio> #include "weak_undef.h" extern int no_such_symbol_ __attribute__ ((weak)); +extern int link_time_only __attribute__ ((weak)); + int *p1 = &no_such_symbol_; +int *p2 = &link_time_only; + int v2 = 42; int @@ -85,5 +95,12 @@ main() status = 1; } + if (p2 != NULL) + { + fprintf(stderr, "FAILED weak undef test 6: %s\n", + "p2 is not NULL"); + status = 1; + } + return status; } |