Warn about undefined references in shared libraries if we have seen

all the DT_NEEDED entries for that library.
This commit is contained in:
Ian Lance Taylor 2007-11-14 07:34:53 +00:00
parent a55ce7febf
commit e2827e5f52
15 changed files with 367 additions and 81 deletions

View file

@ -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)
{
this->error(_("DT_SONAME value out of range: %lld >= %lld"),
static_cast<long long>(val),
static_cast<long long>(strtab_size));
return;
}
const char* strtab = reinterpret_cast<const char*>(strtabu);
this->set_soname_string(strtab + val);
case elfcpp::DT_NULL:
// We should always see DT_NULL at the end of the dynamic
// tags.
return;
}
if (dyn.get_d_tag() == elfcpp::DT_NULL)
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));
else
this->set_soname_string(strtab + val);
}
break;
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;
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

View file

@ -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;

View file

@ -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();

View file

@ -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

View file

@ -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

View file

@ -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),

View file

@ -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_;

View file

@ -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();

View file

@ -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.

View file

@ -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)

View file

@ -28,12 +28,12 @@ TESTS = object_unittest
if GCC
TESTS += debug_msg.sh
check_DATA += debug_msg.err
if NATIVE_LINKER
TESTS += debug_msg.sh undef_symbol.sh
check_DATA += debug_msg.err undef_symbol.err
NATIVE_PROGS = \
constructor_test \
constructor_static_test \
@ -116,19 +116,6 @@ object_unittest_SOURCES = object_unittest.cc
if GCC
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>$@; \
then \
echo 2>&1 "Link of debug_msg.o should have failed"; \
exit 1; \
fi
if NATIVE_LINKER
gcctestdir/ld: ../ld-new
@ -136,6 +123,32 @@ gcctestdir/ld: ../ld-new
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 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 1>&2 "Link of debug_msg.o should have failed"; \
exit 1; \
fi
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
$(CXXCOMPILE) -O0 -c -o $@ $<

View file

@ -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 $@ $<

View file

@ -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;

45
gold/testsuite/undef_symbol.sh Executable file
View file

@ -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

View file

@ -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;
}