Index: archive.cc =================================================================== RCS file: /cvs/src/src/gold/archive.cc,v retrieving revision 1.26 diff -u -p -r1.26 archive.cc --- archive.cc 13 Mar 2008 21:04:21 -0000 1.26 +++ archive.cc 1 Apr 2008 20:52:35 -0000 @@ -26,6 +26,8 @@ #include #include #include +#include "libiberty.h" +#include "filenames.h" #include "elfcpp.h" #include "options.h" @@ -67,26 +69,28 @@ const char Archive::armag[sarmag] = '!', '<', 'a', 'r', 'c', 'h', '>', '\n' }; +const char Archive::armagt[sarmag] = +{ + '!', '<', 't', 'h', 'i', 'n', '>', '\n' +}; + const char Archive::arfmag[2] = { '`', '\n' }; // Set up the archive: read the symbol map and the extended name // table. void -Archive::setup(Task* task) +Archive::setup() { // We need to ignore empty archives. if (this->input_file_->file().filesize() == sarmag) - { - this->input_file_->file().unlock(task); - return; - } + return; // The first member of the archive should be the symbol table. std::string armap_name; section_size_type armap_size = convert_to_section_size_type(this->read_header(sarmag, false, - &armap_name)); + &armap_name, NULL)); off_t off = sarmag; if (armap_name.empty()) { @@ -104,7 +108,7 @@ Archive::setup(Task* task) ++off; std::string xname; section_size_type extended_size = - convert_to_section_size_type(this->read_header(off, true, &xname)); + convert_to_section_size_type(this->read_header(off, true, &xname, NULL)); if (xname == "/") { const unsigned char* p = this->get_view(off + sizeof(Archive_header), @@ -112,9 +116,19 @@ Archive::setup(Task* task) const char* px = reinterpret_cast(p); this->extended_names_.assign(px, extended_size); } +} + +// Unlock any nested archives. - // Opening the file locked it. Unlock it now. - this->input_file_->file().unlock(task); +void +Archive::unlock_nested_archives() +{ + for (Nested_archive_table::iterator p = this->nested_archives_.begin(); + p != this->nested_archives_.end(); + ++p) + { + p->second->unlock(this->task_); + } } // Read the archive symbol map. @@ -161,11 +175,12 @@ Archive::read_armap(off_t start, section // of the member. off_t -Archive::read_header(off_t off, bool cache, std::string* pname) +Archive::read_header(off_t off, bool cache, std::string* pname, + off_t* nested_off) { const unsigned char* p = this->get_view(off, sizeof(Archive_header), cache); const Archive_header* hdr = reinterpret_cast(p); - return this->interpret_header(hdr, off, pname); + return this->interpret_header(hdr, off, pname, nested_off); } // Interpret the header of HDR, the header of the archive member at @@ -174,7 +189,7 @@ Archive::read_header(off_t off, bool cac off_t Archive::interpret_header(const Archive_header* hdr, off_t off, - std::string* pname) + std::string* pname, off_t* nested_off) { if (memcmp(hdr->ar_fmag, arfmag, sizeof arfmag) != 0) { @@ -214,6 +229,8 @@ Archive::interpret_header(const Archive_ return this->input_file_->file().filesize() - off; } pname->assign(hdr->ar_name, name_end - hdr->ar_name); + if (nested_off != NULL) + *nested_off = 0; } else if (hdr->ar_name[1] == ' ') { @@ -229,6 +246,9 @@ Archive::interpret_header(const Archive_ { errno = 0; long x = strtol(hdr->ar_name + 1, &end, 10); + long y = 0; + if (*end == ':') + y = strtol(end + 1, &end, 10); if (*end != ' ' || x < 0 || (x == LONG_MAX && errno == ERANGE) @@ -240,15 +260,17 @@ Archive::interpret_header(const Archive_ } const char* name = this->extended_names_.data() + x; - const char* name_end = strchr(name, '/'); + const char* name_end = strchr(name, '\n'); if (static_cast(name_end - name) > this->extended_names_.size() - || name_end[1] != '\n') + || name_end[-1] != '/') { gold_error(_("%s: bad extended name entry at header %zu"), this->name().c_str(), static_cast(off)); return this->input_file_->file().filesize() - off; } - pname->assign(name, name_end - name); + pname->assign(name, name_end - 1 - name); + if (nested_off != NULL) + *nested_off = y; } return member_size; @@ -348,7 +370,7 @@ Archive::include_all_members(Symbol_tabl const Archive_header* hdr = reinterpret_cast(hdr_buf); std::string name; - off_t size = this->interpret_header(hdr, off, &name); + off_t size = this->interpret_header(hdr, off, &name, NULL); if (name.empty()) { // Symbol table. @@ -360,7 +382,9 @@ Archive::include_all_members(Symbol_tabl else this->include_member(symtab, layout, input_objects, off); - off += sizeof(Archive_header) + size; + off += sizeof(Archive_header); + if (!this->is_thin_archive_) + off += size; if ((off & 1) != 0) ++off; } @@ -374,14 +398,75 @@ Archive::include_member(Symbol_table* sy Input_objects* input_objects, off_t off) { std::string n; - this->read_header(off, false, &n); + off_t nested_off; + this->read_header(off, false, &n, &nested_off); - const off_t memoff = off + static_cast(sizeof(Archive_header)); + Input_file* input_file; + off_t memoff; + + if (!this->is_thin_archive_) + { + input_file = this->input_file_; + memoff = off + static_cast(sizeof(Archive_header)); + } + else + { + // Adjust a relative pathname so that it is relative + // to the directory containing the archive. + if (!IS_ABSOLUTE_PATH(n.c_str())) + { + const char *arch_path = this->name().c_str(); + const char *basename = lbasename(arch_path); + if (basename > arch_path) + n.replace(0, 0, this->name().substr(0, basename - arch_path)); + } + if (nested_off > 0) + { + // This is a member of a nested archive. Open the containing + // archive if we don't already have it open, then do a recursive + // call to include the member from that archive. + Archive* arch; + Nested_archive_table::const_iterator p = + this->nested_archives_.find(n); + if (p != this->nested_archives_.end()) + arch = p->second; + else + { + Input_file_argument* input_file_arg = + new Input_file_argument(n.c_str(), false, "", false, + parameters->options()); + input_file = new Input_file(input_file_arg); + if (!input_file->open(parameters->options(), *this->dirpath_, + this->task_)) + return; + arch = new Archive(n, input_file, false, this->dirpath_, + this->task_); + arch->setup(); + std::pair ins = + this->nested_archives_.insert(std::make_pair(n, arch)); + gold_assert(ins.second); + } + arch->include_member(symtab, layout, input_objects, nested_off); + return; + } + // This is an external member of a thin archive. Open the + // file as a regular relocatable object file. + Input_file_argument* input_file_arg = + new Input_file_argument(n.c_str(), false, "", false, + this->input_file_->options()); + input_file = new Input_file(input_file_arg); + if (!input_file->open(parameters->options(), *this->dirpath_, + this->task_)) + { + return; + } + memoff = 0; + } // Read enough of the file to pick up the entire ELF header. unsigned char ehdr_buf[elfcpp::Elf_sizes<64>::ehdr_size]; - off_t filesize = this->input_file_->file().filesize(); + off_t filesize = input_file->file().filesize(); int read_size = elfcpp::Elf_sizes<64>::ehdr_size; if (filesize - memoff < read_size) read_size = filesize - memoff; @@ -393,7 +478,7 @@ Archive::include_member(Symbol_table* sy return; } - this->input_file_->file().read(memoff, read_size, ehdr_buf); + input_file->file().read(memoff, read_size, ehdr_buf); static unsigned char elfmagic[4] = { @@ -409,7 +494,7 @@ Archive::include_member(Symbol_table* sy Object* obj = make_elf_object((std::string(this->input_file_->filename()) + "(" + n + ")"), - this->input_file_, memoff, ehdr_buf, + input_file, memoff, ehdr_buf, read_size); if (input_objects->add_object(obj)) @@ -425,6 +510,11 @@ Archive::include_member(Symbol_table* sy delete obj; } + if (this->is_thin_archive_) + { + // Opening the file locked it. Unlock it now. + input_file->file().unlock(this->task_); + } } // Add_archive_symbols methods. @@ -461,6 +551,8 @@ Add_archive_symbols::run(Workqueue*) this->archive_->add_symbols(this->symtab_, this->layout_, this->input_objects_); + this->archive_->unlock_nested_archives(); + this->archive_->release(); if (this->input_group_ != NULL) Index: archive.h =================================================================== RCS file: /cvs/src/src/gold/archive.h,v retrieving revision 1.17 diff -u -p -r1.17 archive.h --- archive.h 13 Mar 2008 21:04:21 -0000 1.17 +++ archive.h 1 Apr 2008 20:52:35 -0000 @@ -44,9 +44,11 @@ class Symbol_table; class Archive { public: - Archive(const std::string& name, Input_file* input_file) + Archive(const std::string& name, Input_file* input_file, + bool is_thin_archive, Dirsearch* dirpath, Task* task) : name_(name), input_file_(input_file), armap_(), armap_names_(), - extended_names_(), armap_checked_(), seen_offsets_() + extended_names_(), armap_checked_(), seen_offsets_(), + is_thin_archive_(is_thin_archive), dirpath_(dirpath), task_(task) { } // The length of the magic string at the start of an archive. @@ -54,6 +56,7 @@ class Archive // The magic string at the start of an archive. static const char armag[sarmag]; + static const char armagt[sarmag]; // The string expected at the end of an archive member header. static const char arfmag[2]; @@ -65,7 +68,7 @@ class Archive // Set up the archive: read the symbol map. void - setup(Task*); + setup(); // Get a reference to the underlying file. File_read& @@ -97,6 +100,10 @@ class Archive release() { this->input_file_->file().release(); } + // Unlock any nested archives. + void + unlock_nested_archives(); + // Select members from the archive as needed and add them to the // link. void @@ -121,12 +128,13 @@ class Archive // the file view. Return the size of the member, and set *PNAME to // the name. off_t - read_header(off_t off, bool cache, std::string* pname); + read_header(off_t off, bool cache, std::string* pname, off_t* nested_off); // 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); + interpret_header(const Archive_header* hdr, off_t off, std::string* pname, + off_t* nested_off); // Include all the archive members in the link. void @@ -153,6 +161,9 @@ class Archive { return static_cast(val); } }; + // For keeping track of open nested archives in a thin archive file. + typedef Unordered_map Nested_archive_table; + // Name of object as printed to user. std::string name_; // For reading the file. @@ -168,6 +179,14 @@ class Archive std::vector armap_checked_; // Track which elements have been included by offset. Unordered_set seen_offsets_; + // True if this is a thin archive. + const bool is_thin_archive_; + // Table of nested archives, indexed by filename. + Nested_archive_table nested_archives_; + // The directory search path. + Dirsearch* dirpath_; + // The task reading this archive. + Task *task_; }; // This class is used to read an archive and pick out the desired Index: readsyms.cc =================================================================== RCS file: /cvs/src/src/gold/readsyms.cc,v retrieving revision 1.26 diff -u -p -r1.26 readsyms.cc --- readsyms.cc 13 Mar 2008 21:04:21 -0000 1.26 +++ readsyms.cc 1 Apr 2008 20:52:35 -0000 @@ -204,12 +204,19 @@ Read_symbols::do_read_symbols(Workqueue* if (read_size >= Archive::sarmag) { - if (memcmp(ehdr_buf, Archive::armag, Archive::sarmag) == 0) + bool is_thin_archive + = memcmp(ehdr_buf, Archive::armagt, Archive::sarmag) == 0; + if (is_thin_archive + || memcmp(ehdr_buf, Archive::armag, Archive::sarmag) == 0) { // This is an archive. Archive* arch = new Archive(this->input_argument_->file().name(), - input_file); - arch->setup(this); + input_file, is_thin_archive, + this->dirpath_, this); + arch->setup(); + + // Unlock the archive so it can be used in the next task. + arch->unlock(this); workqueue->queue_next(new Add_archive_symbols(this->symtab_, this->layout_,