diff options
author | Ian Lance Taylor <iant@google.com> | 2007-11-14 07:34:53 +0000 |
---|---|---|
committer | Ian Lance Taylor <iant@google.com> | 2007-11-14 07:34:53 +0000 |
commit | e2827e5f525574e8620bd43c8bcb27dba3407a7f (patch) | |
tree | a72625b3bd98a7beb23dde4aad331598572564f3 | |
parent | a55ce7febfaa52670ce3d9c236d3033de80ac091 (diff) | |
download | gdb-e2827e5f525574e8620bd43c8bcb27dba3407a7f.zip gdb-e2827e5f525574e8620bd43c8bcb27dba3407a7f.tar.gz gdb-e2827e5f525574e8620bd43c8bcb27dba3407a7f.tar.bz2 |
Warn about undefined references in shared libraries if we have seen
all the DT_NEEDED entries for that library.
-rw-r--r-- | gold/dynobj.cc | 95 | ||||
-rw-r--r-- | gold/dynobj.h | 56 | ||||
-rw-r--r-- | gold/gold.cc | 4 | ||||
-rw-r--r-- | gold/object.cc | 26 | ||||
-rw-r--r-- | gold/object.h | 5 | ||||
-rw-r--r-- | gold/options.cc | 9 | ||||
-rw-r--r-- | gold/options.h | 15 | ||||
-rw-r--r-- | gold/parameters.cc | 4 | ||||
-rw-r--r-- | gold/parameters.h | 10 | ||||
-rw-r--r-- | gold/symtab.cc | 20 | ||||
-rw-r--r-- | gold/testsuite/Makefile.am | 37 | ||||
-rw-r--r-- | gold/testsuite/Makefile.in | 43 | ||||
-rw-r--r-- | gold/testsuite/undef_symbol.cc | 38 | ||||
-rwxr-xr-x | gold/testsuite/undef_symbol.sh | 45 | ||||
-rw-r--r-- | gold/testsuite/undef_symbol_main.cc | 29 |
15 files changed, 361 insertions, 75 deletions
diff --git a/gold/dynobj.cc b/gold/dynobj.cc index 9845194..a6f3588 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<int size, bool big_endian> @@ -193,19 +187,20 @@ Sized_dynobj<size, big_endian>::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<int size, bool big_endian> void -Sized_dynobj<size, big_endian>::set_soname(const unsigned char* pshdrs, - unsigned int dynamic_shndx, - unsigned int strtab_shndx, - const unsigned char* strtabu, - off_t strtab_size) +Sized_dynobj<size, big_endian>::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<size, big_endian>::set_soname(const unsigned char* pshdrs, strtabu = this->get_view(strtabshdr.get_sh_offset(), strtab_size, false); } + const char* const strtab = reinterpret_cast<const char*>(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<long long>(val), - static_cast<long long>(strtab_size)); - return; - } + static_cast<long long>(val), + static_cast<long long>(strtab_size)); + else + this->set_soname_string(strtab + val); + } + break; - const char* strtab = reinterpret_cast<const char*>(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<long long>(val), + static_cast<long long>(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<size, big_endian>::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 eb6eb5c..1fe37a4 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<std::string> 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<const char*> Version_map; diff --git a/gold/gold.cc b/gold/gold.cc index a215d0f..d0c2095 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 c0e2acd..fa16d13 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 b8bc65c..3327392 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 d4d9e16..69f452d 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 c54af77..b5d2328 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 @@ -301,6 +307,14 @@ class General_options { 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 f332134..b96221a 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 353f01f..ee60b10 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 9bee283..f5e2132 100644 --- a/gold/symtab.cc +++ b/gold/symtab.cc @@ -1599,6 +1599,26 @@ 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()); + } + 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 e193fc5..520863f 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 dcbbf52..b201423 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 0000000..25fd181 --- /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 <iant@google.com>. + +// 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 0000000..bc9eb57 --- /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 <iant@google.com>. + +# 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 0000000..90f97e0 --- /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 <iant@google.com>. + +// 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; +} |