summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@google.com>2007-11-14 16:53:25 +0000
committerIan Lance Taylor <iant@google.com>2007-11-14 16:53:25 +0000
commit9a2d69841557c502021be98221a796ebe253fa09 (patch)
tree0b92ca469f9782810c95cbbc2e2aa5e80273c669
parent3e6fe5ae738660d48c8b6a3e0206cbd2d23fa1c5 (diff)
downloadbinutils-gdb-9a2d69841557c502021be98221a796ebe253fa09.tar.gz
Add heuristics for undefined symbol warnings.
-rw-r--r--gold/gold.cc2
-rw-r--r--gold/i386.cc5
-rw-r--r--gold/layout.cc4
-rw-r--r--gold/layout.h9
-rw-r--r--gold/object.cc28
-rw-r--r--gold/object.h10
-rw-r--r--gold/options.cc2
-rw-r--r--gold/symtab.cc76
-rw-r--r--gold/symtab.h11
-rw-r--r--gold/target.h11
-rw-r--r--gold/testsuite/Makefile.am7
-rw-r--r--gold/testsuite/Makefile.in7
-rw-r--r--gold/x86_64.cc5
13 files changed, 129 insertions, 48 deletions
diff --git a/gold/gold.cc b/gold/gold.cc
index d0c2095c3f0..2f17add3122 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 eae6b7fa339..7bd5a3a30bd 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 6894264272c..fea056d1a31 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 fa804ad45f1..5b9f28defe6 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 fa16d138549..7a4b1fb41e0 100644
--- a/gold/object.cc
+++ b/gold/object.cc
@@ -25,6 +25,7 @@
#include <cerrno>
#include <cstring>
#include <cstdarg>
+#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<Dynobj*>(obj);
+ const char* soname = dynobj->soname();
std::pair<Unordered_set<std::string>::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 332739295f2..61b40358dde 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<std::string> 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 eff126381b8..69f452dd380 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 f5e21322b78..539bf328c5b 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<int size, bool big_endian>
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<size>::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<size>* sym = static_cast<Sized_symbol<size>*>(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<Dynobj*>(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<Dynobj*>(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 367813fc617..d32112256ab 100644
--- a/gold/symtab.h
+++ b/gold/symtab.h
@@ -46,6 +46,7 @@ class Dynobj;
template<int size, bool big_endian>
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<int size, bool big_endian>
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<int size, bool big_endian>
@@ -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<int size, bool big_endian>
void
diff --git a/gold/target.h b/gold/target.h
index 8ecc078330d..e385c555d81 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 202f3be4e7d..520863fba6c 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 5f860bec382..b2014239169 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 0614e89c606..349d8c1407f 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()