From bc783729096acb5f856a9b0701a884ac4e439c6e Mon Sep 17 00:00:00 2001 From: ian Date: Tue, 22 Jul 2008 22:08:43 +0000 Subject: [PATCH] * cref.cc: New file. * cref.h: New file. * options.h (class General_options): Add --print-symbol-counts. * main.cc (main): Issue defined symbol report if requested. * archive.cc (Archive::interpret_header): Make into a const member function. (Archive::add_symbols): Call Input_objects::archive_start and archive_stop. (Archive::const_iterator): Define new class. (Archive::begin, Archive::end): New functions. (Archive::include_all_members): Rewrite to use iterator. (Archive::count_members): New function. * archive.h (class Archive): Update declarations. (Archive::filename): New function. * object.cc: Include "cref.h". (Sized_relobj::Sized_relobj): Initialize defined_count_. (Sized_relobj::do_get_global_symbol_counts): New function. (Input_objects::add_object): Add object to cross-referencer. (Input_objects::archive_start): New function. (Input_objects::archive_stop): New function. (Input_objects::print_symbol_counts): New function. * object.h: Declare Cref and Archive. (Object::get_global_symbol_counts): New function. (Object::do_get_global_symbol_counts): New pure virtual function. (class Sized_relobj): Add defined_count_ field. Update declarations. (class Input_objects): Add cref_ field. Update constructor. Update declarations. * dynobj.cc (Sized_dynobj::Sized_dynobj): Initialize symbols_ and defined_count_. (Sized_dynobj::do_add_symbols): Allocate symbols_ if printing symbol counts. (Sized_dynobj::do_get_global_symbol_counts): New function. * dynobj.h (class Sized_dynobj): Add fields symbols_ and defined_count_. Update declarations. Define Symbols typedef. * symtab.cc (Symbol_table::add_from_relobj): Add defined parameter. Change all callers. (Symbol_table::add_from_dynobj): Add sympointers and defined parameters. Change all callers. * symtab.h (class Symbol_table): Update declarations. * Makefile.am (CCFILES): Add cref.cc. (HFILES): Add cref.h. * Makefile.in: Rebuild. --- gold/ChangeLog | 48 ++++++++++- gold/Makefile.am | 2 + gold/Makefile.in | 23 ++--- gold/archive.cc | 194 +++++++++++++++++++++++++++++++++--------- gold/archive.h | 31 ++++++- gold/cref.cc | 253 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ gold/cref.h | 73 ++++++++++++++++ gold/dynobj.cc | 39 ++++++++- gold/dynobj.h | 11 +++ gold/main.cc | 4 + gold/object.cc | 67 ++++++++++++++- gold/object.h | 37 +++++++- gold/options.h | 4 + gold/symtab.cc | 53 +++++++++--- gold/symtab.h | 10 ++- 15 files changed, 780 insertions(+), 69 deletions(-) create mode 100644 gold/cref.cc create mode 100644 gold/cref.h diff --git a/gold/ChangeLog b/gold/ChangeLog index 5901d3d18f..ce2a4e316c 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,3 +1,49 @@ +2008-07-22 Ian Lance Taylor + + * cref.cc: New file. + * cref.h: New file. + * options.h (class General_options): Add --print-symbol-counts. + * main.cc (main): Issue defined symbol report if requested. + * archive.cc (Archive::interpret_header): Make into a const member + function. + (Archive::add_symbols): Call Input_objects::archive_start and + archive_stop. + (Archive::const_iterator): Define new class. + (Archive::begin, Archive::end): New functions. + (Archive::include_all_members): Rewrite to use iterator. + (Archive::count_members): New function. + * archive.h (class Archive): Update declarations. + (Archive::filename): New function. + * object.cc: Include "cref.h". + (Sized_relobj::Sized_relobj): Initialize defined_count_. + (Sized_relobj::do_get_global_symbol_counts): New function. + (Input_objects::add_object): Add object to cross-referencer. + (Input_objects::archive_start): New function. + (Input_objects::archive_stop): New function. + (Input_objects::print_symbol_counts): New function. + * object.h: Declare Cref and Archive. + (Object::get_global_symbol_counts): New function. + (Object::do_get_global_symbol_counts): New pure virtual function. + (class Sized_relobj): Add defined_count_ field. Update + declarations. + (class Input_objects): Add cref_ field. Update constructor. + Update declarations. + * dynobj.cc (Sized_dynobj::Sized_dynobj): Initialize symbols_ and + defined_count_. + (Sized_dynobj::do_add_symbols): Allocate symbols_ if printing + symbol counts. + (Sized_dynobj::do_get_global_symbol_counts): New function. + * dynobj.h (class Sized_dynobj): Add fields symbols_ and + defined_count_. Update declarations. Define Symbols typedef. + * symtab.cc (Symbol_table::add_from_relobj): Add defined + parameter. Change all callers. + (Symbol_table::add_from_dynobj): Add sympointers and defined + parameters. Change all callers. + * symtab.h (class Symbol_table): Update declarations. + * Makefile.am (CCFILES): Add cref.cc. + (HFILES): Add cref.h. + * Makefile.in: Rebuild. + 2008-07-22 Simon Baldwin * symtab.cc (Symbol_table::sized_write_symbol): Set symbol size @@ -212,7 +258,7 @@ * reduced_debug_output.cc: New file. * reduced_debug_output.h: New file. - * options.h (class General_optoins): Add --strip-debug-non-line. + * options.h (class General_options): Add --strip-debug-non-line. * options.cc (General_options::finalize): Add strip_debug_non_line to the strip heirarchy. * layout.h (class Layout): Add debug_abbrev_ and debug_info_ diff --git a/gold/Makefile.am b/gold/Makefile.am index 3d1b82a04f..fd5870aefe 100644 --- a/gold/Makefile.am +++ b/gold/Makefile.am @@ -34,6 +34,7 @@ CCFILES = \ common.cc \ compressed_output.cc \ copy-relocs.cc \ + cref.cc \ defstd.cc \ dirsearch.cc \ dynobj.cc \ @@ -70,6 +71,7 @@ HFILES = \ common.h \ compressed_output.h \ copy-relocs.h \ + cref.h \ defstd.h \ dirsearch.h \ dynobj.h \ diff --git a/gold/Makefile.in b/gold/Makefile.in index 48ae0bad4e..242924b288 100644 --- a/gold/Makefile.in +++ b/gold/Makefile.in @@ -76,16 +76,16 @@ libgold_a_AR = $(AR) $(ARFLAGS) libgold_a_LIBADD = am__objects_1 = archive.$(OBJEXT) binary.$(OBJEXT) common.$(OBJEXT) \ compressed_output.$(OBJEXT) copy-relocs.$(OBJEXT) \ - defstd.$(OBJEXT) dirsearch.$(OBJEXT) dynobj.$(OBJEXT) \ - dwarf_reader.$(OBJEXT) ehframe.$(OBJEXT) errors.$(OBJEXT) \ - expression.$(OBJEXT) fileread.$(OBJEXT) gold.$(OBJEXT) \ - gold-threads.$(OBJEXT) layout.$(OBJEXT) mapfile.$(OBJEXT) \ - merge.$(OBJEXT) object.$(OBJEXT) options.$(OBJEXT) \ - output.$(OBJEXT) parameters.$(OBJEXT) readsyms.$(OBJEXT) \ - reduced_debug_output.$(OBJEXT) reloc.$(OBJEXT) \ - resolve.$(OBJEXT) script-sections.$(OBJEXT) script.$(OBJEXT) \ - stringpool.$(OBJEXT) symtab.$(OBJEXT) target-select.$(OBJEXT) \ - version.$(OBJEXT) workqueue.$(OBJEXT) \ + cref.$(OBJEXT) defstd.$(OBJEXT) dirsearch.$(OBJEXT) \ + dynobj.$(OBJEXT) dwarf_reader.$(OBJEXT) ehframe.$(OBJEXT) \ + errors.$(OBJEXT) expression.$(OBJEXT) fileread.$(OBJEXT) \ + gold.$(OBJEXT) gold-threads.$(OBJEXT) layout.$(OBJEXT) \ + mapfile.$(OBJEXT) merge.$(OBJEXT) object.$(OBJEXT) \ + options.$(OBJEXT) output.$(OBJEXT) parameters.$(OBJEXT) \ + readsyms.$(OBJEXT) reduced_debug_output.$(OBJEXT) \ + reloc.$(OBJEXT) resolve.$(OBJEXT) script-sections.$(OBJEXT) \ + script.$(OBJEXT) stringpool.$(OBJEXT) symtab.$(OBJEXT) \ + target-select.$(OBJEXT) version.$(OBJEXT) workqueue.$(OBJEXT) \ workqueue-threads.$(OBJEXT) am__objects_2 = am__objects_3 = yyscript.$(OBJEXT) @@ -316,6 +316,7 @@ CCFILES = \ common.cc \ compressed_output.cc \ copy-relocs.cc \ + cref.cc \ defstd.cc \ dirsearch.cc \ dynobj.cc \ @@ -352,6 +353,7 @@ HFILES = \ common.h \ compressed_output.h \ copy-relocs.h \ + cref.h \ defstd.h \ dirsearch.h \ dynobj.h \ @@ -524,6 +526,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/compressed_output.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/copy-relocs.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cref.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/defstd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dirsearch.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf_reader.Po@am__quote@ diff --git a/gold/archive.cc b/gold/archive.cc index 737f3e2172..8d11797def 100644 --- a/gold/archive.cc +++ b/gold/archive.cc @@ -191,7 +191,7 @@ Archive::read_header(off_t off, bool cache, std::string* pname, off_t Archive::interpret_header(const Archive_header* hdr, off_t off, - std::string* pname, off_t* nested_off) + std::string* pname, off_t* nested_off) const { if (memcmp(hdr->ar_fmag, arfmag, sizeof arfmag) != 0) { @@ -293,6 +293,8 @@ Archive::add_symbols(Symbol_table* symtab, Layout* layout, return this->include_all_members(symtab, layout, input_objects, mapfile); + input_objects->archive_start(this); + const size_t armap_size = this->armap_.size(); // This is a quick optimization, since we usually see many symbols @@ -359,56 +361,170 @@ Archive::add_symbols(Symbol_table* symtab, Layout* layout, } } while (added_new_object); + + input_objects->archive_stop(this); } -// Include all the archive members in the link. This is for --whole-archive. +// An archive member iterator. + +class Archive::const_iterator +{ + public: + // The header of an archive member. This is what this iterator + // points to. + struct Header + { + // The name of the member. + std::string name; + // The file offset of the member. + off_t off; + // The file offset of a nested archive member. + off_t nested_off; + // The size of the member. + off_t size; + }; + + const_iterator(const Archive* archive, off_t off) + : archive_(archive), off_(off) + { this->read_next_header(); } + + const Header& + operator*() const + { return this->header_; } + + const Header* + operator->() const + { return &this->header_; } + + const_iterator& + operator++() + { + if (this->off_ == this->archive_->file().filesize()) + return *this; + this->off_ += sizeof(Archive_header); + if (!this->archive_->is_thin_archive()) + this->off_ += this->header_.size; + if ((this->off_ & 1) != 0) + ++this->off_; + this->read_next_header(); + return *this; + } + + const_iterator + operator++(int) + { + const_iterator ret = *this; + ++*this; + return ret; + } + + bool + operator==(const const_iterator p) const + { return this->off_ == p->off; } + + bool + operator!=(const const_iterator p) const + { return this->off_ != p->off; } + + private: + void + read_next_header(); + + // The underlying archive. + const Archive* archive_; + // The current offset in the file. + off_t off_; + // The current archive header. + Header header_; +}; + +// Read the next archive header. void -Archive::include_all_members(Symbol_table* symtab, Layout* layout, - Input_objects* input_objects, Mapfile* mapfile) +Archive::const_iterator::read_next_header() { - off_t off = sarmag; - off_t filesize = this->input_file_->file().filesize(); + off_t filesize = this->archive_->file().filesize(); while (true) { - if (filesize - off < static_cast(sizeof(Archive_header))) - { - if (filesize != off) - gold_error(_("%s: short archive header at %zu"), - this->name().c_str(), static_cast(off)); - break; - } + if (filesize - this->off_ < static_cast(sizeof(Archive_header))) + { + if (filesize != this->off_) + { + gold_error(_("%s: short archive header at %zu"), + this->archive_->filename().c_str(), + static_cast(this->off_)); + this->off_ = filesize; + } + this->header_.off = filesize; + return; + } - unsigned char hdr_buf[sizeof(Archive_header)]; - this->input_file_->file().read(off, sizeof(Archive_header), hdr_buf); + unsigned char buf[sizeof(Archive_header)]; + this->archive_->file().read(this->off_, sizeof(Archive_header), buf); - const Archive_header* hdr = - reinterpret_cast(hdr_buf); - std::string name; - off_t size = this->interpret_header(hdr, off, &name, NULL); - bool special_member = false; - if (name.empty()) - { - // Symbol table. - special_member = true; - } - else if (name == "/") - { - // Extended name table. - special_member = true; - } - else - this->include_member(symtab, layout, input_objects, off, - mapfile, NULL, "--whole-archive"); - - off += sizeof(Archive_header); - if (special_member || !this->is_thin_archive_) - off += size; - if ((off & 1) != 0) - ++off; + const Archive_header* hdr = reinterpret_cast(buf); + this->header_.size = + this->archive_->interpret_header(hdr, this->off_, &this->header_.name, + &this->header_.nested_off); + this->header_.off = this->off_; + + // Skip special members. + if (!this->header_.name.empty() && this->header_.name != "/") + return; + + this->off_ += sizeof(Archive_header) + this->header_.size; + if ((this->off_ & 1) != 0) + ++this->off_; } } +// Initial iterator. + +Archive::const_iterator +Archive::begin() const +{ + return Archive::const_iterator(this, sarmag); +} + +// Final iterator. + +Archive::const_iterator +Archive::end() const +{ + return Archive::const_iterator(this, this->input_file_->file().filesize()); +} + +// Include all the archive members in the link. This is for --whole-archive. + +void +Archive::include_all_members(Symbol_table* symtab, Layout* layout, + Input_objects* input_objects, Mapfile* mapfile) +{ + input_objects->archive_start(this); + + for (Archive::const_iterator p = this->begin(); + p != this->end(); + ++p) + this->include_member(symtab, layout, input_objects, p->off, + mapfile, NULL, "--whole-archive"); + + input_objects->archive_stop(this); +} + +// Return the number of members in the archive. This is only used for +// reports. + +size_t +Archive::count_members() const +{ + size_t ret = 0; + for (Archive::const_iterator p = this->begin(); + p != this->end(); + ++p) + ++ret; + return ret; +} + // Include an archive member in the link. OFF is the file offset of // the member header. WHY is the reason we are including this member. diff --git a/gold/archive.h b/gold/archive.h index c8b05e442d..53b8452d81 100644 --- a/gold/archive.h +++ b/gold/archive.h @@ -62,11 +62,18 @@ class Archive // The string expected at the end of an archive member header. static const char arfmag[2]; - // The name of the object. + // The name of the object. This is the name used on the command + // line; e.g., if "-lgcc" is on the command line, this will be + // "gcc". const std::string& name() const { return this->name_; } + // The file name. + const std::string& + filename() const + { return this->input_file_->filename(); } + // Set up the archive: read the symbol map. void setup(); @@ -110,6 +117,11 @@ class Archive clear_uncached_views() { this->input_file_->file().clear_uncached_views(); } + // Whether this is a thin archive. + bool + is_thin_archive() const + { return this->is_thin_archive_; } + // Unlock any nested archives. void unlock_nested_archives(); @@ -119,6 +131,10 @@ class Archive void add_symbols(Symbol_table*, Layout*, Input_objects*, Mapfile*); + // Return the number of members in the archive. + size_t + count_members() const; + private: Archive(const Archive&); Archive& operator=(const Archive&); @@ -144,7 +160,7 @@ class Archive // member, and set *PNAME to the name. off_t interpret_header(const Archive_header* hdr, off_t off, std::string* pname, - off_t* nested_off); + off_t* nested_off) const; // Include all the archive members in the link. void @@ -155,6 +171,17 @@ class Archive include_member(Symbol_table*, Layout*, Input_objects*, off_t off, Mapfile*, Symbol*, const char* why); + // Iterate over archive members. + class const_iterator; + + const_iterator + begin() const; + + const_iterator + end() const; + + friend class const_iterator; + // An entry in the archive map of symbols to object files. struct Armap_entry { diff --git a/gold/cref.cc b/gold/cref.cc new file mode 100644 index 0000000000..ec95f36db3 --- /dev/null +++ b/gold/cref.cc @@ -0,0 +1,253 @@ +// cref.cc -- cross reference for gold + +// Copyright 2008 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. + +#include "gold.h" + +#include +#include +#include +#include +#include +#include + +#include "object.h" +#include "archive.h" +#include "cref.h" + +namespace gold +{ + +// Class Cref_inputs. This is used to hold the list of input files +// for cross referencing. + +class Cref_inputs +{ + public: + Cref_inputs() + : objects_(), archives_(), current_(&this->objects_) + { } + + // Add an input object file. + void + add_object(Object* object); + + // Start adding an archive. We support nested archives for future + // flexibility. + void + add_archive_start(Archive*); + + // Finish adding an archive. + void + add_archive_stop(Archive*); + + // Report symbol counts. + void + print_symbol_counts(const Symbol_table*, FILE*) const; + + private: + // A list of input objects. + typedef std::vector Objects; + + // Information we record for an archive. + struct Archive_info + { + // Archive name. + std::string name; + // List of objects included from the archive. + Objects* objects; + // Number of archive members. + size_t member_count; + }; + + // A mapping from the name of an archive to the list of objects in + // that archive. + typedef std::map Archives; + + // Report symbol counts for a list of Objects. + void + print_objects_symbol_counts(const Symbol_table*, FILE*, const Objects*) const; + + // Report symbol counts for an object. + void + print_object_symbol_counts(const Symbol_table*, FILE*, const Object*) const; + + // List of input objects. + Objects objects_; + // List of input archives. This is a mapping from the archive file + // name to the list of objects. + Archives archives_; + // The list to which we are currently adding objects. + Objects* current_; +}; + +// Add an object. + +void +Cref_inputs::add_object(Object* object) +{ + this->current_->push_back(object); +} + +// Start adding an archive. + +void +Cref_inputs::add_archive_start(Archive* archive) +{ + gold_assert(this->current_ == &this->objects_); + if (this->archives_.find(archive->name()) == this->archives_.end()) + { + Archive_info* pai = &this->archives_[archive->name()]; + pai->name = archive->filename(); + pai->objects = new Objects(); + pai->member_count = archive->count_members(); + } + this->current_ = this->archives_[archive->name()].objects; +} + +// Stop adding an archive. + +void +Cref_inputs::add_archive_stop(Archive*) +{ + gold_assert(this->current_ != &this->objects_); + this->current_ = &this->objects_; +} + +// Report symbol counts for an object. + +void +Cref_inputs::print_object_symbol_counts(const Symbol_table* symtab, + FILE* f, + const Object* object) const +{ + size_t defined, used; + object->get_global_symbol_counts(symtab, &defined, &used); + fprintf(f, "symbols %s %zu %zu\n", object->name().c_str(), defined, used); +} + +// Report symbol counts for a list of Inputs. + +void +Cref_inputs::print_objects_symbol_counts(const Symbol_table* symtab, + FILE* f, + const Objects* objects) const +{ + for (Objects::const_iterator p = objects->begin(); + p != objects->end(); + ++p) + this->print_object_symbol_counts(symtab, f, *p); +} + +// Print symbol counts. This implements --print-symbol-counts. This +// is intended to be easily read by a program. This outputs a series +// of lines. There are two different types of lines. + +// The first is "symbols FILENAME DEFINED USED". FILENAME is the name +// of an object file included in the link; for an archive, this will +// be ARCHIVEFILENAME(MEMBERNAME). DEFINED is the number of symbols +// which the object file defines. USED is the number of symbols which +// are used in the final output; this is the number of symbols which +// appear in the final output table as having been defined by this +// object. These numbers will be different when weak symbols are +// used, and they will be different for dynamic objects. + +// The second is "archives FILENAME MEMBERS USED". FILENAME is the +// name of an archive file included in the link. MEMBERS is the +// number of members of the archive. USED is the number of archive +// members included in the link. + +void +Cref_inputs::print_symbol_counts(const Symbol_table* symtab, FILE* f) const +{ + this->print_objects_symbol_counts(symtab, f, &this->objects_); + for (Archives::const_iterator p = this->archives_.begin(); + p != this->archives_.end(); + ++p) + { + fprintf(f, "archive %s %zu %zu\n", p->second.name.c_str(), + p->second.member_count, p->second.objects->size()); + this->print_objects_symbol_counts(symtab, f, p->second.objects); + } +} + +// Class Cref. + +// Make sure the Cref_inputs object has been created. + +void +Cref::need_inputs() +{ + if (this->inputs_ == NULL) + this->inputs_ = new Cref_inputs(); +} + +// Add an input object file. + +void +Cref::add_object(Object* object) +{ + this->need_inputs(); + this->inputs_->add_object(object); +} + +// Start adding an archive. + +void +Cref::add_archive_start(Archive* archive) +{ + this->need_inputs(); + this->inputs_->add_archive_start(archive); +} + +// Stop adding an archive. + +void +Cref::add_archive_stop(Archive* archive) +{ + this->inputs_->add_archive_stop(archive); +} + +// Print symbol counts. + +void +Cref::print_symbol_counts(const Symbol_table* symtab) const +{ + if (parameters->options().user_set_print_symbol_counts() + && this->inputs_ != NULL) + { + FILE* f; + if (strcmp(parameters->options().print_symbol_counts(), "-") == 0) + f = stdout; + else + { + f = fopen(parameters->options().print_symbol_counts(), "w"); + if (f == NULL) + gold_error(_("cannot open symbol count file %s: %s"), + parameters->options().print_symbol_counts(), + strerror(errno)); + } + if (f != NULL) + this->inputs_->print_symbol_counts(symtab, f); + } +} + +} // End namespace gold. diff --git a/gold/cref.h b/gold/cref.h new file mode 100644 index 0000000000..3da5d3ad32 --- /dev/null +++ b/gold/cref.h @@ -0,0 +1,73 @@ +// cref.h -- cross reference reports for gold -*- C++ -*- + +// Copyright 2008 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. + +#ifndef GOLD_CREF_H +#define GOLD_CREF_H + +namespace gold +{ + +class Object; +class Archive; +class Cref_inputs; + +// This class collects data for cross reference and other reporting. + +class Cref +{ + public: + Cref() + : inputs_(NULL) + { } + + // Record an input object file. This is called for each object file + // in the order in which it is processed. + void + add_object(Object*); + + // Start recording an input archive. This is called for each + // archive in the order in which it appears on the command line. A + // call to add_archive_start precedes calls to add_object for each + // object included from the archive. + void + add_archive_start(Archive*); + + // Finish recording an input archive. This is called after + // add_object has been called for each object included from the + // archive. + void + add_archive_stop(Archive*); + + // Print symbol counts. + void + print_symbol_counts(const Symbol_table*) const; + + private: + void + need_inputs(); + + Cref_inputs* inputs_; +}; + +} // End namespace gold. + +#endif // !defined(GOLD_CREF_H) diff --git a/gold/dynobj.cc b/gold/dynobj.cc index a95787d9f5..9247a79d7d 100644 --- a/gold/dynobj.cc +++ b/gold/dynobj.cc @@ -73,7 +73,9 @@ Sized_dynobj::Sized_dynobj( const elfcpp::Ehdr& ehdr) : Dynobj(name, input_file, offset), elf_file_(this, ehdr), - dynsym_shndx_(-1U) + dynsym_shndx_(-1U), + symbols_(NULL), + defined_count_(0) { } @@ -675,6 +677,14 @@ Sized_dynobj::do_add_symbols(Symbol_table* symtab, Version_map version_map; this->make_version_map(sd, &version_map); + // If printing symbol counts, we want to track symbols. + + if (parameters->options().user_set_print_symbol_counts()) + { + this->symbols_ = new Symbols(); + this->symbols_->resize(symcount); + } + const char* sym_names = reinterpret_cast(sd->symbol_names->data()); symtab->add_from_dynobj(this, sd->symbols->data(), symcount, @@ -683,7 +693,9 @@ Sized_dynobj::do_add_symbols(Symbol_table* symtab, ? NULL : sd->versym->data()), sd->versym_size, - &version_map); + &version_map, + this->symbols_, + &this->defined_count_); delete sd->symbols; sd->symbols = NULL; @@ -710,6 +722,29 @@ Sized_dynobj::do_add_symbols(Symbol_table* symtab, this->clear_view_cache_marks(); } +// Get symbol counts. + +template +void +Sized_dynobj::do_get_global_symbol_counts( + const Symbol_table*, + size_t* defined, + size_t* used) const +{ + *defined = this->defined_count_; + size_t count = 0; + for (typename Symbols::const_iterator p = this->symbols_->begin(); + p != this->symbols_->end(); + ++p) + if (*p != NULL + && (*p)->source() == Symbol::FROM_OBJECT + && (*p)->object() == this + && (*p)->is_defined() + && (*p)->dynsym_index() != -1U) + ++count; + *used = count; +} + // Given a vector of hash codes, compute the number of hash buckets to // use. diff --git a/gold/dynobj.h b/gold/dynobj.h index bd5e12dc5e..b5b9bd9725 100644 --- a/gold/dynobj.h +++ b/gold/dynobj.h @@ -156,6 +156,8 @@ template class Sized_dynobj : public Dynobj { public: + typedef typename Sized_relobj::Symbols Symbols; + Sized_dynobj(const std::string& name, Input_file* input_file, off_t offset, const typename elfcpp::Ehdr&); @@ -225,6 +227,10 @@ class Sized_dynobj : public Dynobj Xindex* do_initialize_xindex(); + // Get symbol counts. + void + do_get_global_symbol_counts(const Symbol_table*, size_t*, size_t*) const; + private: // For convenience. typedef Sized_dynobj This; @@ -288,6 +294,11 @@ class Sized_dynobj : public Dynobj elfcpp::Elf_file elf_file_; // The section index of the dynamic symbol table. unsigned int dynsym_shndx_; + // The entries in the symbol table for the symbols. We only keep + // this if we need it to print symbol information. + Symbols* symbols_; + // Number of defined symbols. + size_t defined_count_; }; // A base class for Verdef and Verneed_version which just handles the diff --git a/gold/main.cc b/gold/main.cc index 35772839e4..e10600b195 100644 --- a/gold/main.cc +++ b/gold/main.cc @@ -237,6 +237,10 @@ main(int argc, char** argv) if (mapfile != NULL) mapfile->close(); + // Issue defined symbol report. + if (command_line.options().user_set_print_symbol_counts()) + input_objects.print_symbol_counts(&symtab); + if (parameters->options().fatal_warnings() && errors.warning_count() > 0 && errors.error_count() == 0) diff --git a/gold/object.cc b/gold/object.cc index 2ecb8a9e91..d8f5ec8027 100644 --- a/gold/object.cc +++ b/gold/object.cc @@ -33,6 +33,7 @@ #include "layout.h" #include "output.h" #include "symtab.h" +#include "cref.h" #include "reloc.h" #include "object.h" #include "dynobj.h" @@ -245,6 +246,7 @@ Sized_relobj::Sized_relobj( output_local_symbol_count_(0), output_local_dynsym_count_(0), symbols_(), + defined_count_(0), local_symbol_offset_(0), local_dynsym_offset_(0), local_values_(), @@ -1087,7 +1089,8 @@ Sized_relobj::do_add_symbols(Symbol_table* symtab, sd->symbols->data() + sd->external_symbols_offset, symcount, this->local_symbol_count_, sym_names, sd->symbol_names_size, - &this->symbols_); + &this->symbols_, + &this->defined_count_); delete sd->symbols; sd->symbols = NULL; @@ -1577,6 +1580,28 @@ Sized_relobj::map_to_kept_section( return 0; } +// Get symbol counts. + +template +void +Sized_relobj::do_get_global_symbol_counts( + const Symbol_table*, + size_t* defined, + size_t* used) const +{ + *defined = this->defined_count_; + size_t count = 0; + for (Symbols::const_iterator p = this->symbols_.begin(); + p != this->symbols_.end(); + ++p) + if (*p != NULL + && (*p)->source() == Symbol::FROM_OBJECT + && (*p)->object() == this + && (*p)->is_defined()) + ++count; + *used = count; +} + // Input_objects methods. // Add a regular relocatable object to the list. Return false if this @@ -1631,6 +1656,14 @@ Input_objects::add_object(Object* obj) } } + // Add this object to the cross-referencer if requested. + if (parameters->options().user_set_print_symbol_counts()) + { + if (this->cref_ == NULL) + this->cref_ = new Cref(); + this->cref_->add_object(obj); + } + return true; } @@ -1671,6 +1704,38 @@ Input_objects::check_dynamic_dependencies() const } } +// Start processing an archive. + +void +Input_objects::archive_start(Archive* archive) +{ + if (parameters->options().user_set_print_symbol_counts()) + { + if (this->cref_ == NULL) + this->cref_ = new Cref(); + this->cref_->add_archive_start(archive); + } +} + +// Stop processing an archive. + +void +Input_objects::archive_stop(Archive* archive) +{ + if (parameters->options().user_set_print_symbol_counts()) + this->cref_->add_archive_stop(archive); +} + +// Print symbol counts + +void +Input_objects::print_symbol_counts(const Symbol_table* symtab) const +{ + if (parameters->options().user_set_print_symbol_counts() + && this->cref_ != NULL) + this->cref_->print_symbol_counts(symtab); +} + // 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 df509b23de..7334492fb2 100644 --- a/gold/object.h +++ b/gold/object.h @@ -36,6 +36,8 @@ namespace gold class General_options; class Task; +class Cref; +class Archive; class Layout; class Output_section; class Output_file; @@ -421,6 +423,14 @@ class Object clear_view_cache_marks() { this->input_file()->file().clear_view_cache_marks(); } + // Get the number of global symbols defined by this object, and the + // number of the symbols whose final definition came from this + // object. + void + get_global_symbol_counts(const Symbol_table* symtab, size_t* defined, + size_t* used) const + { this->do_get_global_symbol_counts(symtab, defined, used); } + protected: // Read the symbols--implemented by child class. virtual void @@ -476,6 +486,10 @@ class Object virtual Xindex* do_initialize_xindex() = 0; + // Implement get_global_symbol_counts--implemented by child class. + virtual void + do_get_global_symbol_counts(const Symbol_table*, size_t*, size_t*) const = 0; + // Get the file. We pass on const-ness. Input_file* input_file() @@ -1395,6 +1409,10 @@ class Sized_relobj : public Relobj Xindex* do_initialize_xindex(); + // Get symbol counts. + void + do_get_global_symbol_counts(const Symbol_table*, size_t*, size_t*) const; + // Get the offset of a section. uint64_t do_output_section_offset(unsigned int shndx) const @@ -1628,6 +1646,8 @@ class Sized_relobj : public Relobj unsigned int output_local_dynsym_count_; // The entries in the symbol table for the external symbols. Symbols symbols_; + // Number of symbols defined in object file itself. + size_t defined_count_; // File offset for local symbols. off_t local_symbol_offset_; // File offset for local dynamic symbols. @@ -1655,7 +1675,8 @@ class Input_objects { public: Input_objects() - : relobj_list_(), dynobj_list_(), sonames_(), system_library_directory_() + : relobj_list_(), dynobj_list_(), sonames_(), system_library_directory_(), + cref_(NULL) { } // The type of the list of input relocateable objects. @@ -1671,6 +1692,14 @@ class Input_objects bool add_object(Object*); + // Start processing an archive. + void + archive_start(Archive*); + + // Stop processing an archive. + void + archive_stop(Archive*); + // For each dynamic object, check whether we've seen all of its // explicit dependencies. void @@ -1681,6 +1710,10 @@ class Input_objects bool found_in_system_library_directory(const Object*) const; + // Print symbol counts. + void + print_symbol_counts(const Symbol_table*) const; + // Iterate over all regular objects. Relobj_iterator @@ -1723,6 +1756,8 @@ class Input_objects Unordered_set sonames_; // The directory in which we find the libc.so. std::string system_library_directory_; + // Manage cross-references if requested. + Cref* cref_; }; // Some of the information we pass to the relocation routines. We diff --git a/gold/options.h b/gold/options.h index 653f5fc09d..2641d986ef 100644 --- a/gold/options.h +++ b/gold/options.h @@ -679,6 +679,10 @@ class General_options DEFINE_string(oformat, options::EXACTLY_TWO_DASHES, '\0', "elf", N_("Set output format"), N_("[binary]")); + DEFINE_string(print_symbol_counts, options::TWO_DASHES, '\0', NULL, + N_("Print symbols defined and used for each input"), + N_("FILENAME")); + DEFINE_bool(Qy, options::EXACTLY_ONE_DASH, '\0', false, N_("Ignored for SVR4 compatibility"), NULL); diff --git a/gold/symtab.cc b/gold/symtab.cc index f9bbcc0b2f..03e592e658 100644 --- a/gold/symtab.cc +++ b/gold/symtab.cc @@ -835,8 +835,11 @@ Symbol_table::add_from_relobj( size_t symndx_offset, const char* sym_names, size_t sym_name_size, - typename Sized_relobj::Symbols* sympointers) + typename Sized_relobj::Symbols* sympointers, + size_t *defined) { + *defined = 0; + gold_assert(size == relobj->target()->get_size()); gold_assert(size == parameters->target().get_size()); @@ -847,6 +850,8 @@ Symbol_table::add_from_relobj( const unsigned char* p = syms; for (size_t i = 0; i < count; ++i, p += sym_size) { + (*sympointers)[i] = NULL; + elfcpp::Sym sym(p); unsigned int st_name = sym.get_st_name(); @@ -867,6 +872,9 @@ Symbol_table::add_from_relobj( if (!is_ordinary) orig_st_shndx = elfcpp::SHN_UNDEF; + if (st_shndx != elfcpp::SHN_UNDEF) + ++*defined; + // A symbol defined in a section which we are not including must // be treated as an undefined symbol. if (st_shndx != elfcpp::SHN_UNDEF @@ -977,8 +985,12 @@ Symbol_table::add_from_dynobj( size_t sym_name_size, const unsigned char* versym, size_t versym_size, - const std::vector* version_map) + const std::vector* version_map, + typename Sized_relobj::Symbols* sympointers, + size_t* defined) { + *defined = 0; + gold_assert(size == dynobj->target()->get_size()); gold_assert(size == parameters->target().get_size()); @@ -1012,6 +1024,9 @@ Symbol_table::add_from_dynobj( { elfcpp::Sym sym(p); + if (sympointers != NULL) + (*sympointers)[i] = NULL; + // Ignore symbols with local binding or that have // internal or hidden visibility. if (sym.get_st_bind() == elfcpp::STB_LOCAL @@ -1047,6 +1062,9 @@ Symbol_table::add_from_dynobj( unsigned int st_shndx = dynobj->adjust_sym_shndx(i, psym->get_st_shndx(), &is_ordinary); + if (st_shndx != elfcpp::SHN_UNDEF) + ++*defined; + Sized_symbol* res; if (versym == NULL) @@ -1142,6 +1160,9 @@ Symbol_table::add_from_dynobj( && res->source() == Symbol::FROM_OBJECT && res->object() == dynobj) object_symbols.push_back(res); + + if (sympointers != NULL) + (*sympointers)[i] = res; } this->record_weak_aliases(&object_symbols); @@ -2628,7 +2649,8 @@ Symbol_table::add_from_relobj<32, false>( size_t symndx_offset, const char* sym_names, size_t sym_name_size, - Sized_relobj<32, true>::Symbols* sympointers); + Sized_relobj<32, true>::Symbols* sympointers, + size_t* defined); #endif #ifdef HAVE_TARGET_32_BIG @@ -2641,7 +2663,8 @@ Symbol_table::add_from_relobj<32, true>( size_t symndx_offset, const char* sym_names, size_t sym_name_size, - Sized_relobj<32, false>::Symbols* sympointers); + Sized_relobj<32, false>::Symbols* sympointers, + size_t* defined); #endif #ifdef HAVE_TARGET_64_LITTLE @@ -2654,7 +2677,8 @@ Symbol_table::add_from_relobj<64, false>( size_t symndx_offset, const char* sym_names, size_t sym_name_size, - Sized_relobj<64, true>::Symbols* sympointers); + Sized_relobj<64, true>::Symbols* sympointers, + size_t* defined); #endif #ifdef HAVE_TARGET_64_BIG @@ -2667,7 +2691,8 @@ Symbol_table::add_from_relobj<64, true>( size_t symndx_offset, const char* sym_names, size_t sym_name_size, - Sized_relobj<64, false>::Symbols* sympointers); + Sized_relobj<64, false>::Symbols* sympointers, + size_t* defined); #endif #ifdef HAVE_TARGET_32_LITTLE @@ -2681,7 +2706,9 @@ Symbol_table::add_from_dynobj<32, false>( size_t sym_name_size, const unsigned char* versym, size_t versym_size, - const std::vector* version_map); + const std::vector* version_map, + Sized_relobj<32, false>::Symbols* sympointers, + size_t* defined); #endif #ifdef HAVE_TARGET_32_BIG @@ -2695,7 +2722,9 @@ Symbol_table::add_from_dynobj<32, true>( size_t sym_name_size, const unsigned char* versym, size_t versym_size, - const std::vector* version_map); + const std::vector* version_map, + Sized_relobj<32, true>::Symbols* sympointers, + size_t* defined); #endif #ifdef HAVE_TARGET_64_LITTLE @@ -2709,7 +2738,9 @@ Symbol_table::add_from_dynobj<64, false>( size_t sym_name_size, const unsigned char* versym, size_t versym_size, - const std::vector* version_map); + const std::vector* version_map, + Sized_relobj<64, false>::Symbols* sympointers, + size_t* defined); #endif #ifdef HAVE_TARGET_64_BIG @@ -2723,7 +2754,9 @@ Symbol_table::add_from_dynobj<64, true>( size_t sym_name_size, const unsigned char* versym, size_t versym_size, - const std::vector* version_map); + const std::vector* version_map, + Sized_relobj<64, true>::Symbols* sympointers, + size_t* defined); #endif #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG) diff --git a/gold/symtab.h b/gold/symtab.h index 7d99cd52bb..9afdfe9299 100644 --- a/gold/symtab.h +++ b/gold/symtab.h @@ -1086,14 +1086,16 @@ class Symbol_table // the symbol table. SYMS is the symbols, SYMNDX_OFFSET is the // offset in the symbol table of the first symbol, SYM_NAMES is // their names, SYM_NAME_SIZE is the size of SYM_NAMES. This sets - // SYMPOINTERS to point to the symbols in the symbol table. + // SYMPOINTERS to point to the symbols in the symbol table. It sets + // *DEFINED to the number of defined symbols. template void add_from_relobj(Sized_relobj* relobj, const unsigned char* syms, size_t count, size_t symndx_offset, const char* sym_names, size_t sym_name_size, - typename Sized_relobj::Symbols*); + typename Sized_relobj::Symbols*, + size_t* defined); // Add COUNT dynamic symbols from the dynamic object DYNOBJ to the // symbol table. SYMS is the symbols. SYM_NAMES is their names. @@ -1105,7 +1107,9 @@ class Symbol_table const unsigned char* syms, size_t count, const char* sym_names, size_t sym_name_size, const unsigned char* versym, size_t versym_size, - const std::vector*); + const std::vector*, + typename Sized_relobj::Symbols*, + size_t* defined); // Define a special symbol based on an Output_data. It is a // multiple definition error if this symbol is already defined. -- 2.11.0