From e2827e5f525574e8620bd43c8bcb27dba3407a7f Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 14 Nov 2007 07:34:53 +0000 Subject: [PATCH] Warn about undefined references in shared libraries if we have seen all the DT_NEEDED entries for that library. --- gold/dynobj.cc | 95 ++++++++++++++++------------- gold/dynobj.h | 56 +++++++++++++++-- gold/gold.cc | 4 ++ gold/object.cc | 26 ++++++++ gold/object.h | 5 ++ gold/options.cc | 9 +++ gold/options.h | 15 +++++ gold/parameters.cc | 4 +- gold/parameters.h | 10 +++ gold/symtab.cc | 20 ++++++ gold/testsuite/Makefile.am | 37 +++++++---- gold/testsuite/Makefile.in | 43 ++++++++----- gold/testsuite/undef_symbol.cc | 38 ++++++++++++ gold/testsuite/undef_symbol.sh | 45 ++++++++++++++ gold/testsuite/undef_symbol_main.cc | 29 +++++++++ 15 files changed, 361 insertions(+), 75 deletions(-) create mode 100644 gold/testsuite/undef_symbol.cc create mode 100755 gold/testsuite/undef_symbol.sh create mode 100644 gold/testsuite/undef_symbol_main.cc diff --git a/gold/dynobj.cc b/gold/dynobj.cc index 9845194b3b6..a6f3588f48c 100644 --- a/gold/dynobj.cc +++ b/gold/dynobj.cc @@ -39,7 +39,9 @@ namespace gold // see a DT_SONAME entry. Dynobj::Dynobj(const std::string& name, Input_file* input_file, off_t offset) - : Object(name, input_file, true, offset) + : Object(name, input_file, true, offset), + needed_(), + unknown_needed_(UNKNOWN_NEEDED_UNSET) { // This will be overridden by a DT_SONAME entry, hopefully. But if // we never see a DT_SONAME entry, our rule is to use the dynamic @@ -60,14 +62,6 @@ Dynobj::Dynobj(const std::string& name, Input_file* input_file, off_t offset) } } -// Return the string to use in a DT_NEEDED entry. - -const char* -Dynobj::soname() const -{ - return this->soname_.c_str(); -} - // Class Sized_dynobj. template @@ -193,19 +187,20 @@ Sized_dynobj::read_dynsym_section( *view_info = shdr.get_sh_info(); } -// Set the soname field if this shared object has a DT_SONAME tag. -// PSHDRS points to the section headers. DYNAMIC_SHNDX is the section -// index of the SHT_DYNAMIC section. STRTAB_SHNDX, STRTAB, and -// STRTAB_SIZE are the section index and contents of a string table -// which may be the one associated with the SHT_DYNAMIC section. +// Read the dynamic tags. Set the soname field if this shared object +// has a DT_SONAME tag. Record the DT_NEEDED tags. PSHDRS points to +// the section headers. DYNAMIC_SHNDX is the section index of the +// SHT_DYNAMIC section. STRTAB_SHNDX, STRTAB, and STRTAB_SIZE are the +// section index and contents of a string table which may be the one +// associated with the SHT_DYNAMIC section. template void -Sized_dynobj::set_soname(const unsigned char* pshdrs, - unsigned int dynamic_shndx, - unsigned int strtab_shndx, - const unsigned char* strtabu, - off_t strtab_size) +Sized_dynobj::read_dynamic(const unsigned char* pshdrs, + unsigned int dynamic_shndx, + unsigned int strtab_shndx, + const unsigned char* strtabu, + off_t strtab_size) { typename This::Shdr dynamicshdr(pshdrs + dynamic_shndx * This::shdr_size); gold_assert(dynamicshdr.get_sh_type() == elfcpp::SHT_DYNAMIC); @@ -236,30 +231,48 @@ Sized_dynobj::set_soname(const unsigned char* pshdrs, strtabu = this->get_view(strtabshdr.get_sh_offset(), strtab_size, false); } + const char* const strtab = reinterpret_cast(strtabu); + for (const unsigned char* p = pdynamic; p < pdynamic + dynamic_size; p += This::dyn_size) { typename This::Dyn dyn(p); - if (dyn.get_d_tag() == elfcpp::DT_SONAME) + switch (dyn.get_d_tag()) { - off_t val = dyn.get_d_val(); - if (val >= strtab_size) - { + case elfcpp::DT_NULL: + // We should always see DT_NULL at the end of the dynamic + // tags. + return; + + case elfcpp::DT_SONAME: + { + off_t val = dyn.get_d_val(); + if (val >= strtab_size) this->error(_("DT_SONAME value out of range: %lld >= %lld"), - static_cast(val), - static_cast(strtab_size)); - return; - } + static_cast(val), + static_cast(strtab_size)); + else + this->set_soname_string(strtab + val); + } + break; - const char* strtab = reinterpret_cast(strtabu); - this->set_soname_string(strtab + val); - return; - } + case elfcpp::DT_NEEDED: + { + off_t val = dyn.get_d_val(); + if (val >= strtab_size) + this->error(_("DT_NEEDED value out of range: %lld >= %lld"), + static_cast(val), + static_cast(strtab_size)); + else + this->add_needed(strtab + val); + } + break; - if (dyn.get_d_tag() == elfcpp::DT_NULL) - return; + default: + break; + } } this->error(_("missing DT_NULL in dynamic segment")); @@ -346,15 +359,15 @@ Sized_dynobj::do_read_symbols(Read_symbols_data* sd) } // Read the SHT_DYNAMIC section to find whether this shared object - // has a DT_SONAME tag. This doesn't really have anything to do - // with reading the symbols, but this is a convenient place to do - // it. + // has a DT_SONAME tag and to record any DT_NEEDED tags. This + // doesn't really have anything to do with reading the symbols, but + // this is a convenient place to do it. if (dynamic_shndx != -1U) - this->set_soname(pshdrs, dynamic_shndx, strtab_shndx, - (sd->symbol_names == NULL - ? NULL - : sd->symbol_names->data()), - sd->symbol_names_size); + this->read_dynamic(pshdrs, dynamic_shndx, strtab_shndx, + (sd->symbol_names == NULL + ? NULL + : sd->symbol_names->data()), + sd->symbol_names_size); } // Lay out the input sections for a dynamic object. We don't want to diff --git a/gold/dynobj.h b/gold/dynobj.h index eb6eb5c1cf5..1fe37a4b600 100644 --- a/gold/dynobj.h +++ b/gold/dynobj.h @@ -39,11 +39,38 @@ class General_options; class Dynobj : public Object { public: + // We keep a list of all the DT_NEEDED entries we find. + typedef std::vector Needed; + Dynobj(const std::string& name, Input_file* input_file, off_t offset = 0); // Return the name to use in a DT_NEEDED entry for this object. const char* - soname() const; + soname() const + { return this->soname_.c_str(); } + + // Return the list of DT_NEEDED strings. + const Needed& + needed() const + { return this->needed_; } + + // Return whether this dynamic object has any DT_NEEDED entries + // which were not seen during the link. + bool + has_unknown_needed_entries() const + { + gold_assert(this->unknown_needed_ != UNKNOWN_NEEDED_UNSET); + return this->unknown_needed_ == UNKNOWN_NEEDED_TRUE; + } + + // Set whether this dynamic object has any DT_NEEDED entries which + // were not seen during the link. + void + set_has_unknown_needed_entries(bool set) + { + gold_assert(this->unknown_needed_ == UNKNOWN_NEEDED_UNSET); + this->unknown_needed_ = set ? UNKNOWN_NEEDED_TRUE : UNKNOWN_NEEDED_FALSE; + } // Compute the ELF hash code for a string. static uint32_t @@ -74,6 +101,11 @@ class Dynobj : public Object set_soname_string(const char* s) { this->soname_.assign(s); } + // Add an entry to the list of DT_NEEDED strings. + void + add_needed(const char* s) + { this->needed_.push_back(std::string(s)); } + private: // Compute the GNU hash code for a string. static uint32_t @@ -101,8 +133,21 @@ class Dynobj : public Object unsigned char** pphash, unsigned int* phashlen); + // Values for the has_unknown_needed_entries_ field. + enum Unknown_needed + { + UNKNOWN_NEEDED_UNSET, + UNKNOWN_NEEDED_TRUE, + UNKNOWN_NEEDED_FALSE + }; + // The DT_SONAME name, if any. std::string soname_; + // The list of DT_NEEDED entries. + Needed needed_; + // Whether this dynamic object has any DT_NEEDED entries not seen + // during the link. + Unknown_needed unknown_needed_; }; // A dynamic object, size and endian specific version. @@ -187,12 +232,11 @@ class Sized_dynobj : public Dynobj File_view** view, off_t* view_size, unsigned int* view_info); - // Set the SONAME from the SHT_DYNAMIC section at DYNAMIC_SHNDX. - // The STRTAB parameters may have the relevant string table. + // Read the dynamic tags. void - set_soname(const unsigned char* pshdrs, unsigned int dynamic_shndx, - unsigned int strtab_shndx, const unsigned char* strtabu, - off_t strtab_size); + read_dynamic(const unsigned char* pshdrs, unsigned int dynamic_shndx, + unsigned int strtab_shndx, const unsigned char* strtabu, + off_t strtab_size); // Mapping from version number to version name. typedef std::vector Version_map; diff --git a/gold/gold.cc b/gold/gold.cc index a215d0f31dc..d0c2095c3f0 100644 --- a/gold/gold.cc +++ b/gold/gold.cc @@ -180,6 +180,10 @@ queue_middle_tasks(const General_options& options, (*input_objects->dynobj_begin())->name().c_str()); } + // For each dynamic object, record whether we've seen all the + // dynamic objects that it depends upon. + input_objects->check_dynamic_dependencies(); + // See if any of the input definitions violate the One Definition Rule. // TODO: if this is too slow, do this as a task, rather than inline. symtab->detect_odr_violations(); diff --git a/gold/object.cc b/gold/object.cc index c0e2acd4e77..fa16d138549 100644 --- a/gold/object.cc +++ b/gold/object.cc @@ -1080,6 +1080,32 @@ Input_objects::add_object(Object* obj) return true; } +// For each dynamic object, record whether we've seen all of its +// explicit dependencies. + +void +Input_objects::check_dynamic_dependencies() const +{ + for (Dynobj_list::const_iterator p = this->dynobj_list_.begin(); + p != this->dynobj_list_.end(); + ++p) + { + const Dynobj::Needed& needed((*p)->needed()); + bool found_all = true; + for (Dynobj::Needed::const_iterator pneeded = needed.begin(); + pneeded != needed.end(); + ++pneeded) + { + if (this->sonames_.find(*pneeded) == this->sonames_.end()) + { + found_all = false; + break; + } + } + (*p)->set_has_unknown_needed_entries(!found_all); + } +} + // Relocate_info methods. // Return a string describing the location of a relocation. This is diff --git a/gold/object.h b/gold/object.h index b8bc65c9098..332739295f2 100644 --- a/gold/object.h +++ b/gold/object.h @@ -951,6 +951,11 @@ class Input_objects target() const { return this->target_; } + // For each dynamic object, check whether we've seen all of its + // explicit dependencies. + void + check_dynamic_dependencies() const; + // Iterate over all regular objects. Relobj_iterator diff --git a/gold/options.cc b/gold/options.cc index d4d9e16cc2b..69f452dd380 100644 --- a/gold/options.cc +++ b/gold/options.cc @@ -337,6 +337,14 @@ namespace gold const options::One_option options::Command_line_options::options[] = { + GENERAL_NOARG('\0', "allow-shlib-undefined", + N_("Allow unresolved references in shared libraries"), + NULL, TWO_DASHES, + &General_options::set_allow_shlib_undefined), + GENERAL_NOARG('\0', "no-allow-shlib-undefined", + N_("Do not allow unresolved references in shared libraries"), + NULL, TWO_DASHES, + &General_options::set_no_allow_shlib_undefined), POSDEP_NOARG('\0', "as-needed", N_("Only set DT_NEEDED for dynamic libs if used"), NULL, TWO_DASHES, &Position_dependent_options::set_as_needed), @@ -475,6 +483,7 @@ General_options::General_options() output_file_name_("a.out"), is_relocatable_(false), strip_(STRIP_NONE), + allow_shlib_undefined_(false), symbolic_(false), detect_odr_violations_(false), create_eh_frame_hdr_(false), diff --git a/gold/options.h b/gold/options.h index c54af7781d2..b5d2328a1a6 100644 --- a/gold/options.h +++ b/gold/options.h @@ -148,6 +148,12 @@ class General_options strip_debug() const { return this->strip_ == STRIP_ALL || this->strip_ == STRIP_DEBUG; } + // --allow-shlib-undefined: do not warn about unresolved symbols in + // --shared libraries. + bool + allow_shlib_undefined() const + { return this->allow_shlib_undefined_; } + // -Bsymbolic: bind defined symbols locally. bool symbolic() const @@ -300,6 +306,14 @@ class General_options set_strip_debug() { this->strip_ = STRIP_DEBUG; } + void + set_allow_shlib_undefined() + { this->allow_shlib_undefined_ = true; } + + void + set_no_allow_shlib_undefined() + { this->allow_shlib_undefined_ = false; } + void set_symbolic() { this->symbolic_ = true; } @@ -420,6 +434,7 @@ class General_options const char* output_file_name_; bool is_relocatable_; Strip strip_; + bool allow_shlib_undefined_; bool symbolic_; bool detect_odr_violations_; bool create_eh_frame_hdr_; diff --git a/gold/parameters.cc b/gold/parameters.cc index f332134d4b6..b96221a8b24 100644 --- a/gold/parameters.cc +++ b/gold/parameters.cc @@ -33,7 +33,8 @@ namespace gold Parameters::Parameters(Errors* errors) : errors_(errors), output_file_name_(NULL), output_file_type_(OUTPUT_INVALID), sysroot_(), - strip_(STRIP_INVALID), symbolic_(false), detect_odr_violations_(false), + strip_(STRIP_INVALID), allow_shlib_undefined_(false), + symbolic_(false), detect_odr_violations_(false), optimization_level_(0), export_dynamic_(false), is_doing_static_link_valid_(false), doing_static_link_(false), is_size_and_endian_valid_(false), size_(0), is_big_endian_(false) @@ -47,6 +48,7 @@ Parameters::set_from_options(const General_options* options) { this->output_file_name_ = options->output_file_name(); this->sysroot_ = options->sysroot(); + this->allow_shlib_undefined_ = options->allow_shlib_undefined(); this->symbolic_ = options->symbolic(); this->detect_odr_violations_ = options->detect_odr_violations(); this->optimization_level_ = options->optimization_level(); diff --git a/gold/parameters.h b/gold/parameters.h index 353f01f2ba8..ee60b10b4a0 100644 --- a/gold/parameters.h +++ b/gold/parameters.h @@ -112,6 +112,14 @@ class Parameters return this->strip_ == STRIP_ALL || this->strip_ == STRIP_DEBUG; } + // Whether to permit unresolved references from shared libraries. + bool + allow_shlib_undefined() const + { + gold_assert(this->options_valid_); + return this->allow_shlib_undefined_; + } + // Whether we are doing a symbolic link, in which all defined // symbols are bound locally. bool @@ -224,6 +232,8 @@ class Parameters std::string sysroot_; // Which symbols to strip. Strip strip_; + // Whether to allow undefined references from shared libraries. + bool allow_shlib_undefined_; // Whether we are doing a symbolic link. bool symbolic_; // Whether we try to detect One Definition Rule violations. diff --git a/gold/symtab.cc b/gold/symtab.cc index 9bee2837db3..f5e21322b78 100644 --- a/gold/symtab.cc +++ b/gold/symtab.cc @@ -1599,6 +1599,26 @@ 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()); + } + unsigned int sym_index = sym->symtab_index(); unsigned int dynsym_index; if (dynamic_view == NULL) diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am index e193fc56028..520863fba6c 100644 --- a/gold/testsuite/Makefile.am +++ b/gold/testsuite/Makefile.am @@ -28,11 +28,11 @@ TESTS = object_unittest if GCC -TESTS += debug_msg.sh +if NATIVE_LINKER -check_DATA += debug_msg.err +TESTS += debug_msg.sh undef_symbol.sh -if NATIVE_LINKER +check_DATA += debug_msg.err undef_symbol.err NATIVE_PROGS = \ constructor_test \ @@ -116,25 +116,38 @@ object_unittest_SOURCES = object_unittest.cc if GCC +if NATIVE_LINKER + +gcctestdir/ld: ../ld-new + test -d gcctestdir || mkdir -p gcctestdir + rm -f gcctestdir/ld + (cd gcctestdir && $(LN_S) ../../ld-new ld) + debug_msg.o: debug_msg.cc $(CXXCOMPILE) -O0 -g -c -w -o $@ $(srcdir)/debug_msg.cc odr_violation1.o: odr_violation1.cc $(CXXCOMPILE) -O0 -g -c -w -o $@ $(srcdir)/odr_violation1.cc odr_violation2.o: odr_violation2.cc $(CXXCOMPILE) -O0 -g -c -w -o $@ $(srcdir)/odr_violation2.cc -debug_msg.err: debug_msg.o odr_violation1.o odr_violation2.o - if $(CXXLINK) -Bgcctestdir/ -Wl,--detect-odr-violations -o debug_msg debug_msg.o odr_violation1.o odr_violation2.o 2>$@; \ +debug_msg.err: debug_msg.o odr_violation1.o odr_violation2.o gcctestdir/ld + @echo $(CXXLINK) -Bgcctestdir/ -Wl,--detect-odr-violations -o debug_msg debug_msg.o odr_violation1.o odr_violation2.o "2>$@" + @if $(CXXLINK) -Bgcctestdir/ -Wl,--detect-odr-violations -o debug_msg debug_msg.o odr_violation1.o odr_violation2.o 2>$@; \ then \ - echo 2>&1 "Link of debug_msg.o should have failed"; \ + echo 1>&2 "Link of debug_msg.o should have failed"; \ exit 1; \ fi -if NATIVE_LINKER - -gcctestdir/ld: ../ld-new - test -d gcctestdir || mkdir -p gcctestdir - rm -f gcctestdir/ld - (cd gcctestdir && $(LN_S) ../../ld-new ld) +undef_symbol.o: undef_symbol.cc + $(CXXCOMPILE) -O0 -g -c -fPIC $< +undef_symbol.so: undef_symbol.o + $(CXXLINK) -shared undef_symbol.o +undef_symbol.err: undef_symbol_main.o undef_symbol.so gcctestdir/ld + @echo $(CXXLINK) -Bgcctestdir/ -o undef_symbol_test undef_symbol_main.o undef_symbol.so "2>$@" + @if $(CXXLINK) -Bgcctestdir/ -o undef_symbol_test undef_symbol_main.o undef_symbol.so 2>$@; \ + then \ + echo 1>&2 "Link of undef_symbol_test should have failed"; \ + exit 1; \ + fi # Override the default CXXFLAGS--we don't want any optimization basic_test.o: basic_test.cc diff --git a/gold/testsuite/Makefile.in b/gold/testsuite/Makefile.in index dcbbf520044..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@am__append_1 = debug_msg.sh -@GCC_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 \ @@ -1204,24 +1204,37 @@ uninstall-am: uninstall-info-am tags uninstall uninstall-am uninstall-info-am -@GCC_TRUE@debug_msg.o: debug_msg.cc -@GCC_TRUE@ $(CXXCOMPILE) -O0 -g -c -w -o $@ $(srcdir)/debug_msg.cc -@GCC_TRUE@odr_violation1.o: odr_violation1.cc -@GCC_TRUE@ $(CXXCOMPILE) -O0 -g -c -w -o $@ $(srcdir)/odr_violation1.cc -@GCC_TRUE@odr_violation2.o: odr_violation2.cc -@GCC_TRUE@ $(CXXCOMPILE) -O0 -g -c -w -o $@ $(srcdir)/odr_violation2.cc -@GCC_TRUE@debug_msg.err: debug_msg.o odr_violation1.o odr_violation2.o -@GCC_TRUE@ if $(CXXLINK) -Bgcctestdir/ -Wl,--detect-odr-violations -o debug_msg debug_msg.o odr_violation1.o odr_violation2.o 2>$@; \ -@GCC_TRUE@ then \ -@GCC_TRUE@ echo 2>&1 "Link of debug_msg.o should have failed"; \ -@GCC_TRUE@ exit 1; \ -@GCC_TRUE@ fi - @GCC_TRUE@@NATIVE_LINKER_TRUE@gcctestdir/ld: ../ld-new @GCC_TRUE@@NATIVE_LINKER_TRUE@ test -d gcctestdir || mkdir -p gcctestdir @GCC_TRUE@@NATIVE_LINKER_TRUE@ rm -f gcctestdir/ld @GCC_TRUE@@NATIVE_LINKER_TRUE@ (cd gcctestdir && $(LN_S) ../../ld-new ld) +@GCC_TRUE@@NATIVE_LINKER_TRUE@debug_msg.o: debug_msg.cc +@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -g -c -w -o $@ $(srcdir)/debug_msg.cc +@GCC_TRUE@@NATIVE_LINKER_TRUE@odr_violation1.o: odr_violation1.cc +@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -g -c -w -o $@ $(srcdir)/odr_violation1.cc +@GCC_TRUE@@NATIVE_LINKER_TRUE@odr_violation2.o: odr_violation2.cc +@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -g -c -w -o $@ $(srcdir)/odr_violation2.cc +@GCC_TRUE@@NATIVE_LINKER_TRUE@debug_msg.err: debug_msg.o odr_violation1.o odr_violation2.o gcctestdir/ld +@GCC_TRUE@@NATIVE_LINKER_TRUE@ @echo $(CXXLINK) -Bgcctestdir/ -Wl,--detect-odr-violations -o debug_msg debug_msg.o odr_violation1.o odr_violation2.o "2>$@" +@GCC_TRUE@@NATIVE_LINKER_TRUE@ @if $(CXXLINK) -Bgcctestdir/ -Wl,--detect-odr-violations -o debug_msg debug_msg.o odr_violation1.o odr_violation2.o 2>$@; \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ then \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ echo 1>&2 "Link of debug_msg.o should have failed"; \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ exit 1; \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ fi + +@GCC_TRUE@@NATIVE_LINKER_TRUE@undef_symbol.o: undef_symbol.cc +@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -g -c -fPIC $< +@GCC_TRUE@@NATIVE_LINKER_TRUE@undef_symbol.so: undef_symbol.o +@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -shared undef_symbol.o +@GCC_TRUE@@NATIVE_LINKER_TRUE@undef_symbol.err: undef_symbol_main.o undef_symbol.so gcctestdir/ld +@GCC_TRUE@@NATIVE_LINKER_TRUE@ @echo $(CXXLINK) -Bgcctestdir/ -o undef_symbol_test undef_symbol_main.o undef_symbol.so "2>$@" +@GCC_TRUE@@NATIVE_LINKER_TRUE@ @if $(CXXLINK) -Bgcctestdir/ -o undef_symbol_test undef_symbol_main.o undef_symbol.so 2>$@; \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ then \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ echo 1>&2 "Link of undef_symbol_test should have failed"; \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ exit 1; \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ fi + # Override the default CXXFLAGS--we don't want any optimization @GCC_TRUE@@NATIVE_LINKER_TRUE@basic_test.o: basic_test.cc @GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -c -o $@ $< diff --git a/gold/testsuite/undef_symbol.cc b/gold/testsuite/undef_symbol.cc new file mode 100644 index 00000000000..25fd1813f38 --- /dev/null +++ b/gold/testsuite/undef_symbol.cc @@ -0,0 +1,38 @@ +// undef_symbol.cc -- a test case for undefined references + +// Copyright 2007 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// This file is part of gold. + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, +// MA 02110-1301, USA. + +// This file is constructed to have an undefined reference to the +// global variable a. We should get an error when we link. + +extern int a; + +class Foo +{ + public: + Foo() + : a_(a) + { } + private: + int a_; +}; + +static Foo foo; diff --git a/gold/testsuite/undef_symbol.sh b/gold/testsuite/undef_symbol.sh new file mode 100755 index 00000000000..bc9eb570e1a --- /dev/null +++ b/gold/testsuite/undef_symbol.sh @@ -0,0 +1,45 @@ +#!/bin/sh + +# undef_symbol.sh -- a test case for undefined symbols in shared libraries + +# Copyright 2007 Free Software Foundation, Inc. +# Written by Ian Lance Taylor . + +# This file is part of gold. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, +# MA 02110-1301, USA. + +# This file goes with debug_msg.cc, a C++ source file constructed to +# have undefined references. We compile that file with debug +# information and then try to link it, and make sure the proper errors +# are displayed. The errors will be found in debug_msg.err. + +check() +{ + if ! grep -q "$1" undef_symbol.err + then + echo "Did not find expected error:" + echo " $1" + echo "" + echo "Actual error output below:" + cat undef_symbol.err + exit 1 + fi +} + +check "undef_symbol.so: undefined reference to 'a'" + +exit 0 diff --git a/gold/testsuite/undef_symbol_main.cc b/gold/testsuite/undef_symbol_main.cc new file mode 100644 index 00000000000..90f97e07a59 --- /dev/null +++ b/gold/testsuite/undef_symbol_main.cc @@ -0,0 +1,29 @@ +// undef_symbol_1.cc -- a test case for undefined references + +// Copyright 2007 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// This file is part of gold. + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, +// MA 02110-1301, USA. + +// Main function for undefined symbol test. + +int +main() +{ + return 0; +} -- 2.30.2