From 9a2d69841557c502021be98221a796ebe253fa09 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 14 Nov 2007 16:53:25 +0000 Subject: [PATCH] Add heuristics for undefined symbol warnings. --- gold/gold.cc | 2 +- gold/i386.cc | 5 +++ gold/layout.cc | 4 +- gold/layout.h | 9 +++-- gold/object.cc | 28 +++++++++++++- gold/object.h | 10 ++++- gold/options.cc | 2 +- gold/symtab.cc | 76 +++++++++++++++++++++++++------------- gold/symtab.h | 11 ++++-- gold/target.h | 11 ++++++ gold/testsuite/Makefile.am | 7 +--- gold/testsuite/Makefile.in | 7 +--- gold/x86_64.cc | 5 +++ 13 files changed, 129 insertions(+), 48 deletions(-) diff --git a/gold/gold.cc b/gold/gold.cc index d0c2095c3f..2f17add312 100644 --- a/gold/gold.cc +++ b/gold/gold.cc @@ -286,7 +286,7 @@ queue_final_tasks(const General_options& options, // Queue a task to write out the symbol table. final_blocker->add_blocker(); workqueue->queue(new Write_symbols_task(symtab, - input_objects->target(), + input_objects, layout->sympool(), layout->dynpool(), of, diff --git a/gold/i386.cc b/gold/i386.cc index eae6b7fa33..7bd5a3a30b 100644 --- a/gold/i386.cc +++ b/gold/i386.cc @@ -100,6 +100,11 @@ class Target_i386 : public Sized_target<32, false> std::string do_code_fill(off_t length); + // Return whether SYM is defined by the ABI. + bool + do_is_defined_by_abi(Symbol* sym) const + { return strcmp(sym->name(), "___tls_get_addr") == 0; } + // Return the size of the GOT section. off_t got_size() diff --git a/gold/layout.cc b/gold/layout.cc index 6894264272..fea056d1a3 100644 --- a/gold/layout.cc +++ b/gold/layout.cc @@ -1928,8 +1928,8 @@ Write_symbols_task::locks(Workqueue* workqueue) void Write_symbols_task::run(Workqueue*) { - this->symtab_->write_globals(this->target_, this->sympool_, this->dynpool_, - this->of_); + this->symtab_->write_globals(this->input_objects_, this->sympool_, + this->dynpool_, this->of_); } // Write_after_input_sections_task methods. diff --git a/gold/layout.h b/gold/layout.h index fa804ad45f..5b9f28defe 100644 --- a/gold/layout.h +++ b/gold/layout.h @@ -506,11 +506,12 @@ class Write_data_task : public Task class Write_symbols_task : public Task { public: - Write_symbols_task(const Symbol_table* symtab, const Target* target, + Write_symbols_task(const Symbol_table* symtab, + const Input_objects* input_objects, const Stringpool* sympool, const Stringpool* dynpool, Output_file* of, Task_token* final_blocker) - : symtab_(symtab), target_(target), sympool_(sympool), dynpool_(dynpool), - of_(of), final_blocker_(final_blocker) + : symtab_(symtab), input_objects_(input_objects), sympool_(sympool), + dynpool_(dynpool), of_(of), final_blocker_(final_blocker) { } // The standard Task methods. @@ -526,7 +527,7 @@ class Write_symbols_task : public Task private: const Symbol_table* symtab_; - const Target* target_; + const Input_objects* input_objects_; const Stringpool* sympool_; const Stringpool* dynpool_; Output_file* of_; diff --git a/gold/object.cc b/gold/object.cc index fa16d13854..7a4b1fb41e 100644 --- a/gold/object.cc +++ b/gold/object.cc @@ -25,6 +25,7 @@ #include #include #include +#include "libiberty.h" #include "target-select.h" #include "dwarf_reader.h" @@ -1062,9 +1063,10 @@ Input_objects::add_object(Object* obj) { // See if this is a duplicate SONAME. Dynobj* dynobj = static_cast(obj); + const char* soname = dynobj->soname(); std::pair::iterator, bool> ins = - this->sonames_.insert(dynobj->soname()); + this->sonames_.insert(soname); if (!ins.second) { // We have already seen a dynamic object with this soname. @@ -1072,6 +1074,19 @@ Input_objects::add_object(Object* obj) } this->dynobj_list_.push_back(dynobj); + + // If this is -lc, remember the directory in which we found it. + // We use this when issuing warnings about undefined symbols: as + // a heuristic, we don't warn about system libraries found in + // the same directory as -lc. + if (strncmp(soname, "libc.so", 7) == 0) + { + const char* object_name = dynobj->name().c_str(); + const char* base = lbasename(object_name); + if (base != object_name) + this->system_library_directory_.assign(object_name, + base - 1 - object_name); + } } set_parameters_size_and_endianness(target->get_size(), @@ -1080,6 +1095,17 @@ Input_objects::add_object(Object* obj) return true; } +// Return whether an object was found in the system library directory. + +bool +Input_objects::found_in_system_library_directory(const Object* object) const +{ + return (!this->system_library_directory_.empty() + && object->name().compare(0, + this->system_library_directory_.size(), + this->system_library_directory_) == 0); +} + // For each dynamic object, record whether we've seen all of its // explicit dependencies. diff --git a/gold/object.h b/gold/object.h index 332739295f..61b40358dd 100644 --- a/gold/object.h +++ b/gold/object.h @@ -930,7 +930,8 @@ class Input_objects { public: Input_objects() - : relobj_list_(), dynobj_list_(), target_(NULL), sonames_() + : relobj_list_(), dynobj_list_(), target_(NULL), sonames_(), + system_library_directory_() { } // The type of the list of input relocateable objects. @@ -956,6 +957,11 @@ class Input_objects void check_dynamic_dependencies() const; + // Return whether an object was found in the system library + // directory. + bool + found_in_system_library_directory(const Object*) const; + // Iterate over all regular objects. Relobj_iterator @@ -998,6 +1004,8 @@ class Input_objects Target* target_; // SONAMEs that we have seen. Unordered_set sonames_; + // The directory in which we find the libc.so. + std::string system_library_directory_; }; // Some of the information we pass to the relocation routines. We diff --git a/gold/options.cc b/gold/options.cc index eff126381b..69f452dd38 100644 --- a/gold/options.cc +++ b/gold/options.cc @@ -483,7 +483,7 @@ General_options::General_options() output_file_name_("a.out"), is_relocatable_(false), strip_(STRIP_NONE), - allow_shlib_undefined_(true), + allow_shlib_undefined_(false), symbolic_(false), detect_odr_violations_(false), create_eh_frame_hdr_(false), diff --git a/gold/symtab.cc b/gold/symtab.cc index f5e21322b7..539bf328c5 100644 --- a/gold/symtab.cc +++ b/gold/symtab.cc @@ -1524,7 +1524,8 @@ Symbol_table::sized_finalize(unsigned index, off_t off, Stringpool* pool) // Write out the global symbols. void -Symbol_table::write_globals(const Target* target, const Stringpool* sympool, +Symbol_table::write_globals(const Input_objects* input_objects, + const Stringpool* sympool, const Stringpool* dynpool, Output_file* of) const { if (parameters->get_size() == 32) @@ -1532,7 +1533,8 @@ Symbol_table::write_globals(const Target* target, const Stringpool* sympool, if (parameters->is_big_endian()) { #ifdef HAVE_TARGET_32_BIG - this->sized_write_globals<32, true>(target, sympool, dynpool, of); + this->sized_write_globals<32, true>(input_objects, sympool, + dynpool, of); #else gold_unreachable(); #endif @@ -1540,7 +1542,8 @@ Symbol_table::write_globals(const Target* target, const Stringpool* sympool, else { #ifdef HAVE_TARGET_32_LITTLE - this->sized_write_globals<32, false>(target, sympool, dynpool, of); + this->sized_write_globals<32, false>(input_objects, sympool, + dynpool, of); #else gold_unreachable(); #endif @@ -1551,7 +1554,8 @@ Symbol_table::write_globals(const Target* target, const Stringpool* sympool, if (parameters->is_big_endian()) { #ifdef HAVE_TARGET_64_BIG - this->sized_write_globals<64, true>(target, sympool, dynpool, of); + this->sized_write_globals<64, true>(input_objects, sympool, + dynpool, of); #else gold_unreachable(); #endif @@ -1559,7 +1563,8 @@ Symbol_table::write_globals(const Target* target, const Stringpool* sympool, else { #ifdef HAVE_TARGET_64_LITTLE - this->sized_write_globals<64, false>(target, sympool, dynpool, of); + this->sized_write_globals<64, false>(input_objects, sympool, + dynpool, of); #else gold_unreachable(); #endif @@ -1573,11 +1578,13 @@ Symbol_table::write_globals(const Target* target, const Stringpool* sympool, template void -Symbol_table::sized_write_globals(const Target* target, +Symbol_table::sized_write_globals(const Input_objects* input_objects, const Stringpool* sympool, const Stringpool* dynpool, Output_file* of) const { + const Target* const target = input_objects->target(); + const int sym_size = elfcpp::Elf_sizes::sym_size; unsigned int index = this->first_global_index_; const off_t oview_size = this->output_count_ * sym_size; @@ -1599,25 +1606,8 @@ Symbol_table::sized_write_globals(const Target* target, { Sized_symbol* sym = static_cast*>(p->second); - // Optionally check for unresolved symbols in shared libraries. - // This is controlled by the --allow-shlib-undefined option. We - // only warn about libraries for which we have seen all the - // DT_NEEDED entries. We don't try to track down DT_NEEDED - // entries which were not seen in this link. If we didn't see a - // DT_NEEDED entry, we aren't going to be able to reliably - // report whether the symbol is undefined. - if (sym->source() == Symbol::FROM_OBJECT - && sym->object()->is_dynamic() - && sym->shndx() == elfcpp::SHN_UNDEF - && sym->binding() != elfcpp::STB_WEAK - && !parameters->allow_shlib_undefined()) - { - // A very ugly cast. - Dynobj* dynobj = static_cast(sym->object()); - if (!dynobj->has_unknown_needed_entries()) - gold_error(_("%s: undefined reference to '%s'"), - sym->object()->name().c_str(), sym->name()); - } + // Possibly warn about unresolved symbols in shared libraries. + this->warn_about_undefined_dynobj_symbol(input_objects, sym); unsigned int sym_index = sym->symtab_index(); unsigned int dynsym_index; @@ -1749,6 +1739,42 @@ Symbol_table::sized_write_symbol( osym.put_st_shndx(shndx); } +// Check for unresolved symbols in shared libraries. This is +// controlled by the --allow-shlib-undefined option. + +// We only warn about libraries for which we have seen all the +// DT_NEEDED entries. We don't try to track down DT_NEEDED entries +// which were not seen in this link. If we didn't see a DT_NEEDED +// entry, we aren't going to be able to reliably report whether the +// symbol is undefined. + +// We also don't warn about libraries found in the system library +// directory (the directory were we find libc.so); we assume that +// those libraries are OK. This heuristic avoids problems in +// GNU/Linux, in which -ldl can have undefined references satisfied by +// ld-linux.so. + +inline void +Symbol_table::warn_about_undefined_dynobj_symbol( + const Input_objects* input_objects, + Symbol* sym) const +{ + if (sym->source() == Symbol::FROM_OBJECT + && sym->object()->is_dynamic() + && sym->shndx() == elfcpp::SHN_UNDEF + && sym->binding() != elfcpp::STB_WEAK + && !parameters->allow_shlib_undefined() + && !input_objects->target()->is_defined_by_abi(sym) + && !input_objects->found_in_system_library_directory(sym->object())) + { + // A very ugly cast. + Dynobj* dynobj = static_cast(sym->object()); + if (!dynobj->has_unknown_needed_entries()) + gold_error(_("%s: undefined reference to '%s'"), + sym->object()->name().c_str(), sym->name()); + } +} + // Write out a section symbol. Return the update offset. void diff --git a/gold/symtab.h b/gold/symtab.h index 367813fc61..d32112256a 100644 --- a/gold/symtab.h +++ b/gold/symtab.h @@ -46,6 +46,7 @@ class Dynobj; template class Sized_dynobj; class Versions; +class Input_objects; class Output_data; class Output_section; class Output_segment; @@ -1055,7 +1056,7 @@ class Symbol_table // Write out the global symbols. void - write_globals(const Target*, const Stringpool*, const Stringpool*, + write_globals(const Input_objects*, const Stringpool*, const Stringpool*, Output_file*) const; // Write out a section symbol. Return the updated offset. @@ -1177,8 +1178,8 @@ class Symbol_table // Write globals specialized for size and endianness. template void - sized_write_globals(const Target*, const Stringpool*, const Stringpool*, - Output_file*) const; + sized_write_globals(const Input_objects*, const Stringpool*, + const Stringpool*, Output_file*) const; // Write out a symbol to P. template @@ -1189,6 +1190,10 @@ class Symbol_table const Stringpool*, unsigned char* p ACCEPT_SIZE_ENDIAN) const; + // Possibly warn about an undefined symbol from a dynamic object. + void + warn_about_undefined_dynobj_symbol(const Input_objects*, Symbol*) const; + // Write out a section symbol, specialized for size and endianness. template void diff --git a/gold/target.h b/gold/target.h index 8ecc078330..e385c555d8 100644 --- a/gold/target.h +++ b/gold/target.h @@ -137,6 +137,12 @@ class Target code_fill(off_t length) { return this->do_code_fill(length); } + // Return whether SYM is known to be defined by the ABI. This is + // used to avoid inappropriate warnings about undefined symbols. + bool + is_defined_by_abi(Symbol* sym) const + { return this->do_is_defined_by_abi(sym); } + protected: // This struct holds the constant information for a child class. We // use a struct to avoid the overhead of virtual function calls for @@ -188,6 +194,11 @@ class Target do_code_fill(off_t) { gold_unreachable(); } + // Virtual function which may be implemented by the child class. + virtual bool + do_is_defined_by_abi(Symbol*) const + { return false; } + private: Target(const Target&); Target& operator=(const Target&); diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am index 202f3be4e7..520863fba6 100644 --- a/gold/testsuite/Makefile.am +++ b/gold/testsuite/Makefile.am @@ -30,12 +30,9 @@ if GCC if NATIVE_LINKER -TESTS += debug_msg.sh +TESTS += debug_msg.sh undef_symbol.sh -check_DATA += debug_msg.err - -# TESTS += undef_symbol.sh -# check_DATA +=undef_symbol.err +check_DATA += debug_msg.err undef_symbol.err NATIVE_PROGS = \ constructor_test \ diff --git a/gold/testsuite/Makefile.in b/gold/testsuite/Makefile.in index 5f860bec38..b201423916 100644 --- a/gold/testsuite/Makefile.in +++ b/gold/testsuite/Makefile.in @@ -42,8 +42,8 @@ POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ -@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_1 = debug_msg.sh -@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_2 = debug_msg.err +@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_1 = debug_msg.sh undef_symbol.sh +@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_2 = debug_msg.err undef_symbol.err @FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_3 = \ @FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared_1_nonpic_test \ @FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared_2_nonpic_test \ @@ -573,9 +573,6 @@ INCLUDES = \ check_SCRIPTS = debug_msg.sh check_DATA = $(am__append_2) TESTS = object_unittest $(am__append_1) $(NATIVE_TESTING) - -# TESTS += undef_symbol.sh -# check_DATA +=undef_symbol.err @GCC_TRUE@@NATIVE_LINKER_TRUE@NATIVE_PROGS = constructor_test \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ constructor_static_test \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_test \ diff --git a/gold/x86_64.cc b/gold/x86_64.cc index 0614e89c60..349d8c1407 100644 --- a/gold/x86_64.cc +++ b/gold/x86_64.cc @@ -113,6 +113,11 @@ class Target_x86_64 : public Sized_target<64, false> std::string do_code_fill(off_t length); + // Return whether SYM is defined by the ABI. + bool + do_is_defined_by_abi(Symbol* sym) const + { return strcmp(sym->name(), "__tls_get_addr") == 0; } + // Return the size of the GOT section. off_t got_size() -- 2.34.1