From 4973341a7d985b4d211b0b2ce14d95e2c05dbd37 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 21 Aug 2007 23:37:56 +0000 Subject: Implement --whole-archive. --- gold/archive.cc | 116 +++++++++++++++++++++++++++++++++++++++++++++----------- gold/archive.h | 18 ++++++++- gold/fileread.h | 12 ++++-- gold/options.cc | 13 ++++++- gold/options.h | 15 ++++++++ 5 files changed, 146 insertions(+), 28 deletions(-) (limited to 'gold') diff --git a/gold/archive.cc b/gold/archive.cc index d085403..51a0f48 100644 --- a/gold/archive.cc +++ b/gold/archive.cc @@ -57,16 +57,45 @@ Archive::setup() // The first member of the archive should be the symbol table. std::string armap_name; off_t armap_size = this->read_header(sarmag, &armap_name); - if (!armap_name.empty()) + off_t off; + if (armap_name.empty()) + { + this->read_armap(sarmag + sizeof(Archive_header), armap_size); + off = sarmag + sizeof(Archive_header) + armap_size; + } + else if (!this->input_file_->options().include_whole_archive()) { fprintf(stderr, _("%s: %s: no archive symbol table (run ranlib)\n"), program_name, this->name().c_str()); gold_exit(false); } + else + off = sarmag; + + // See if there is an extended name table. + if ((off & 1) != 0) + ++off; + std::string xname; + off_t extended_size = this->read_header(off, &xname); + if (xname == "/") + { + const unsigned char* p = this->get_view(off + sizeof(Archive_header), + extended_size); + const char* px = reinterpret_cast(p); + this->extended_names_.assign(px, extended_size); + } + + // Opening the file locked it. Unlock it now. + this->input_file_->file().unlock(); +} +// Read the archive symbol map. + +void +Archive::read_armap(off_t start, off_t size) +{ // Read in the entire armap. - const unsigned char* p = this->get_view(sarmag + sizeof(Archive_header), - armap_size); + const unsigned char* p = this->get_view(start, size); // Numbers in the armap are always big-endian. const elfcpp::Elf_Word* pword = reinterpret_cast(p); @@ -86,32 +115,16 @@ Archive::setup() ++pword; } - if (reinterpret_cast(pnames) - p > armap_size) + if (reinterpret_cast(pnames) - p > size) { fprintf(stderr, _("%s: %s: bad archive symbol table names\n"), program_name, this->name().c_str()); gold_exit(false); } - // See if there is an extended name table. - off_t off = sarmag + sizeof(Archive_header) + armap_size; - if ((off & 1) != 0) - ++off; - std::string xname; - off_t extended_size = this->read_header(off, &xname); - if (xname == "/") - { - p = this->get_view(off + sizeof(Archive_header), extended_size); - const char* px = reinterpret_cast(p); - this->extended_names_.assign(px, extended_size); - } - // This array keeps track of which symbols are for archive elements // which we have already included in the link. this->seen_.resize(nsyms); - - // Opening the file locked it. Unlock it now. - this->input_file_->file().unlock(); } // Read the header of an archive member at OFF. Fail if something @@ -123,7 +136,17 @@ Archive::read_header(off_t off, std::string* pname) { const unsigned char* p = this->get_view(off, sizeof(Archive_header)); const Archive_header* hdr = reinterpret_cast(p); + return this->interpret_header(hdr, off, pname); +} +// Interpret the header of HDR, the header of the archive member at +// file offset OFF. Fail if something goes wrong. Return the size of +// the member. Set *PNAME to the name of the member. + +off_t +Archive::interpret_header(const Archive_header* hdr, off_t off, + std::string* pname) +{ if (memcmp(hdr->ar_fmag, arfmag, sizeof arfmag) != 0) { fprintf(stderr, _("%s; %s: malformed archive header at %ld\n"), @@ -218,6 +241,9 @@ void Archive::add_symbols(const General_options& options, Symbol_table* symtab, Layout* layout, Input_objects* input_objects) { + if (this->input_file_->options().include_whole_archive()) + return this->include_all_members(options, symtab, layout, input_objects); + const size_t armap_size = this->armap_.size(); bool added_new_object; @@ -256,6 +282,52 @@ Archive::add_symbols(const General_options& options, Symbol_table* symtab, while (added_new_object); } +// Include all the archive members in the link. This is for --whole-archive. + +void +Archive::include_all_members(const General_options& options, + Symbol_table* symtab, Layout* layout, + Input_objects* input_objects) +{ + off_t off = sarmag; + while (true) + { + off_t bytes; + const unsigned char* p = this->get_view(off, sizeof(Archive_header), + &bytes); + if (bytes < sizeof(Archive_header)) + { + if (bytes != 0) + { + fprintf(stderr, _("%s: %s: short archive header at %ld\n"), + program_name, this->name().c_str(), + static_cast(off)); + gold_exit(false); + } + + break; + } + + const Archive_header* hdr = reinterpret_cast(p); + std::string name; + off_t size = this->interpret_header(hdr, off, &name); + if (name.empty()) + { + // Symbol table. + } + else if (name == "/") + { + // Extended name table. + } + else + this->include_member(options, symtab, layout, input_objects, off); + + off += sizeof(Archive_header) + size; + if ((off & 1) != 0) + ++off; + } +} + // Include an archive member in the link. OFF is the file offset of // the member header. @@ -339,7 +411,7 @@ class Add_archive_symbols::Add_archive_symbols_locker : public Task_locker private: Task_locker_block blocker_; - Task_locker_obj filelock_; + Task_locker_obj filelock_; }; Task_locker* @@ -354,7 +426,7 @@ void Add_archive_symbols::run(Workqueue*) { this->archive_->add_symbols(this->options_, this->symtab_, this->layout_, - this->input_objects_); + this->input_objects_); if (this->input_group_ != NULL) this->input_group_->add_archive(this->archive_); diff --git a/gold/archive.h b/gold/archive.h index 193a9e2..ddd665f 100644 --- a/gold/archive.h +++ b/gold/archive.h @@ -79,14 +79,28 @@ class Archive // Get a view into the underlying file. const unsigned char* - get_view(off_t start, off_t size) - { return this->input_file_->file().get_view(start, size); } + get_view(off_t start, off_t size, off_t* pbytes = NULL) + { return this->input_file_->file().get_view(start, size, pbytes); } + + // Read the archive symbol map. + void + read_armap(off_t start, off_t size); // Read an archive member header at OFF. Return the size of the // member, and set *PNAME to the name. off_t read_header(off_t off, std::string* pname); + // Interpret an archive header HDR at OFF. Return the size of the + // member, and set *PNAME to the name. + off_t + interpret_header(const Archive_header* hdr, off_t off, std::string* pname); + + // Include all the archive members in the link. + void + include_all_members(const General_options&, Symbol_table*, Layout*, + Input_objects*); + // Include an archive member in the link. void include_member(const General_options&, Symbol_table*, Layout*, diff --git a/gold/fileread.h b/gold/fileread.h index 178e7f3..f3ac753 100644 --- a/gold/fileread.h +++ b/gold/fileread.h @@ -55,7 +55,7 @@ class File_read // Unlock the descriptor, permitting it to be closed if necessary. void unlock(); - + // Test whether the object is locked. bool is_locked(); @@ -65,12 +65,12 @@ class File_read // we can not read enough data. Otherwise *PBYTES is set to the // number of bytes read. const unsigned char* - get_view(off_t start, off_t size, off_t *pbytes = NULL); + get_view(off_t start, off_t size, off_t* pbytes = NULL); // Read data from the file into the buffer P. PBYTES is as in // get_view. void - read(off_t start, off_t size, void* p, off_t *pbytes = NULL); + read(off_t start, off_t size, void* p, off_t* pbytes = NULL); // Return a lasting view into the file. This is allocated with new, // and the caller is responsible for deleting it when done. The @@ -240,6 +240,12 @@ class Input_file filename() const { return this->file_.filename(); } + // Return the position dependent options. + const Position_dependent_options& + options() const + { return this->input_argument_->options(); } + + // Return the file. File_read& file() { return this->file_; } diff --git a/gold/options.cc b/gold/options.cc index 36e0044..0b858a2 100644 --- a/gold/options.cc +++ b/gold/options.cc @@ -257,6 +257,14 @@ options::Command_line_options::options[] = POSDEP_NOARG('\0', "no-as-needed", N_("Always DT_NEEDED for following dynamic libs (default)"), NULL, TWO_DASHES, &Position_dependent_options::clear_as_needed), + POSDEP_NOARG('\0', "whole-archive", + N_("Include all archive contents"), + NULL, TWO_DASHES, + &Position_dependent_options::set_whole_archive), + POSDEP_NOARG('\0', "no-whole-archive", + N_("Include only needed archive contents"), + NULL, TWO_DASHES, + &Position_dependent_options::clear_whole_archive), SPECIAL('\0', "help", N_("Report usage information"), NULL, TWO_DASHES, &help) }; @@ -271,6 +279,7 @@ General_options::General_options() search_path_(), output_file_name_("a.out"), is_relocatable_(false), + rpath_(), is_shared_(false), is_static_(false) { @@ -279,7 +288,9 @@ General_options::General_options() // The default values for the position dependent options. Position_dependent_options::Position_dependent_options() - : do_static_search_(false) + : do_static_search_(false), + as_needed_(false), + include_whole_archive_(false) { } diff --git a/gold/options.h b/gold/options.h index dc38b2f..3c13deb 100644 --- a/gold/options.h +++ b/gold/options.h @@ -142,6 +142,12 @@ class Position_dependent_options as_needed() const { return this->as_needed_; } + // --whole-archive: Whether to include the entire contents of an + // --archive. + bool + include_whole_archive() const + { return this->include_whole_archive_; } + void set_static_search() { this->do_static_search_ = true; } @@ -158,9 +164,18 @@ class Position_dependent_options clear_as_needed() { this->as_needed_ = false; } + void + set_whole_archive() + { this->include_whole_archive_ = true; } + + void + clear_whole_archive() + { this->include_whole_archive_ = false; } + private: bool do_static_search_; bool as_needed_; + bool include_whole_archive_; }; // A single file or library argument from the command line. -- cgit v1.1