From cb29561284eaa37c5c8967e49a5db0a4064368bf Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 2 Jan 2008 23:48:49 +0000 Subject: Reduce the number of system calls. Use readv instead of pread. Do better handling of cached views. --- gold/archive.cc | 18 +++-- gold/archive.h | 7 +- gold/dynobj.cc | 6 +- gold/fileread.cc | 212 ++++++++++++++++++++++++++++++++++++++++++++++++------- gold/fileread.h | 72 ++++++++++++++++++- gold/layout.cc | 5 +- gold/layout.h | 3 +- gold/object.cc | 27 ++++--- gold/object.h | 67 +++++++++++------- gold/reloc.cc | 46 +++++++++++- gold/symtab.cc | 31 ++------ gold/symtab.h | 30 ++++---- 12 files changed, 404 insertions(+), 120 deletions(-) (limited to 'gold') diff --git a/gold/archive.cc b/gold/archive.cc index 53b5cd0..2125608 100644 --- a/gold/archive.cc +++ b/gold/archive.cc @@ -85,7 +85,8 @@ Archive::setup(Task* task) // 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, &armap_name)); + convert_to_section_size_type(this->read_header(sarmag, false, + &armap_name)); off_t off = sarmag; if (armap_name.empty()) { @@ -96,15 +97,18 @@ Archive::setup(Task* task) gold_error(_("%s: no archive symbol table (run ranlib)"), this->name().c_str()); - // See if there is an extended name table. + // See if there is an extended name table. We cache these views + // because it is likely that we will want to read the following + // header in the add_symbols routine. if ((off & 1) != 0) ++off; std::string xname; - off_t extended_size = this->read_header(off, &xname); + section_size_type extended_size = + convert_to_section_size_type(this->read_header(off, true, &xname)); if (xname == "/") { const unsigned char* p = this->get_view(off + sizeof(Archive_header), - extended_size, false); + extended_size, true); const char* px = reinterpret_cast(p); this->extended_names_.assign(px, extended_size); } @@ -157,9 +161,9 @@ Archive::read_armap(off_t start, section_size_type size) // of the member. off_t -Archive::read_header(off_t off, std::string* pname) +Archive::read_header(off_t off, bool cache, std::string* pname) { - const unsigned char* p = this->get_view(off, sizeof(Archive_header), false); + 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); } @@ -370,7 +374,7 @@ Archive::include_member(Symbol_table* symtab, Layout* layout, Input_objects* input_objects, off_t off) { std::string n; - this->read_header(off, &n); + this->read_header(off, false, &n); const off_t memoff = off + static_cast(sizeof(Archive_header)); diff --git a/gold/archive.h b/gold/archive.h index fb83ea6..0dfaf92 100644 --- a/gold/archive.h +++ b/gold/archive.h @@ -117,10 +117,11 @@ class Archive void read_armap(off_t start, section_size_type size); - // Read an archive member header at OFF. Return the size of the - // member, and set *PNAME to the name. + // Read an archive member header at OFF. CACHE is whether to cache + // the file view. Return the size of the member, and set *PNAME to + // the name. off_t - read_header(off_t off, std::string* pname); + read_header(off_t off, bool cache, std::string* pname); // Interpret an archive header HDR at OFF. Return the size of the // member, and set *PNAME to the name. diff --git a/gold/dynobj.cc b/gold/dynobj.cc index 7e61007..3c3549d 100644 --- a/gold/dynobj.cc +++ b/gold/dynobj.cc @@ -335,7 +335,7 @@ Sized_dynobj::do_read_symbols(Read_symbols_data* sd) sd->symbol_names = this->get_lasting_view(strtabshdr.get_sh_offset(), strtabshdr.get_sh_size(), - true); + false); sd->symbol_names_size = convert_to_section_size_type(strtabshdr.get_sh_size()); @@ -667,6 +667,10 @@ Sized_dynobj::do_add_symbols(Symbol_table* symtab, delete sd->verneed; sd->verneed = NULL; } + + // This is normally the last time we will read any data from this + // file. + this->clear_view_cache_marks(); } // Given a vector of hash codes, compute the number of hash buckets to diff --git a/gold/fileread.cc b/gold/fileread.cc index defb3a0..010c2ee 100644 --- a/gold/fileread.cc +++ b/gold/fileread.cc @@ -27,6 +27,7 @@ #include #include #include +#include #include "filenames.h" #include "options.h" @@ -194,11 +195,21 @@ inline File_read::View* File_read::find_view(off_t start, section_size_type size) const { off_t page = File_read::page_offset(start); - Views::const_iterator p = this->views_.find(page); - if (p == this->views_.end()) - return NULL; - if (p->second->size() - (start - page) < size) + + Views::const_iterator p = this->views_.lower_bound(page); + if (p == this->views_.end() || p->first > page) + { + if (p == this->views_.begin()) + return NULL; + --p; + } + + if (p->second->start() + static_cast(p->second->size()) + < start + static_cast(size)) return NULL; + + p->second->set_accessed(); + return p->second; } @@ -244,7 +255,7 @@ File_read::do_read(off_t start, section_size_type size, void* p) const void File_read::read(off_t start, section_size_type size, void* p) const { - File_read::View* pv = this->find_view(start, size); + const File_read::View* pv = this->find_view(start, size); if (pv != NULL) { memcpy(p, pv->data() + (start - pv->start()), size); @@ -262,6 +273,14 @@ File_read::find_or_make_view(off_t start, section_size_type size, bool cache) gold_assert(!this->token_.is_writable()); this->released_ = false; + File_read::View* v = this->find_view(start, size); + if (v != NULL) + { + if (cache) + v->set_cache(); + return v; + } + off_t poff = File_read::page_offset(start); File_read::View* const vnull = NULL; @@ -270,21 +289,19 @@ File_read::find_or_make_view(off_t start, section_size_type size, bool cache) if (!ins.second) { - // There was an existing view at this offset. - File_read::View* v = ins.first->second; - if (v->size() - (start - v->start()) >= size) - { - if (cache) - v->set_cache(); - return v; - } - - // This view is not large enough. + // There was an existing view at this offset. It must not be + // large enough. We can't delete it here, since something might + // be using it; put it on a list to be deleted when the file is + // unlocked. + v = ins.first->second; + gold_assert(v->size() - (start - v->start()) < size); + if (v->should_cache()) + cache = true; + v->clear_cache(); this->saved_views_.push_back(v); } - // We need to read data from the file. We read full pages for - // greater efficiency on small files. + // We need to map data from the file. section_size_type psize = File_read::pages(size + (start - poff)); @@ -294,8 +311,6 @@ File_read::find_or_make_view(off_t start, section_size_type size, bool cache) gold_assert(psize >= size); } - File_read::View* v; - if (this->contents_ != NULL) { unsigned char* p = new unsigned char[psize]; @@ -304,7 +319,7 @@ File_read::find_or_make_view(off_t start, section_size_type size, bool cache) } else { - void* p = ::mmap(NULL, psize, PROT_READ, MAP_SHARED, + void* p = ::mmap(NULL, psize, PROT_READ, MAP_PRIVATE, this->descriptor_, poff); if (p == MAP_FAILED) gold_fatal(_("%s: mmap offset %lld size %lld failed: %s"), @@ -340,7 +355,143 @@ File_read::get_lasting_view(off_t start, section_size_type size, bool cache) return new File_view(*this, pv, pv->data() + (start - pv->start())); } -// Remove all the file views. +// Use readv to read COUNT entries from RM starting at START. BASE +// must be added to all file offsets in RM. + +void +File_read::do_readv(off_t base, const Read_multiple& rm, size_t start, + size_t count) +{ + unsigned char discard[File_read::page_size]; + iovec iov[File_read::max_readv_entries * 2]; + size_t iov_index = 0; + + off_t first_offset = rm[start].file_offset; + off_t last_offset = first_offset; + ssize_t want = 0; + for (size_t i = 0; i < count; ++i) + { + const Read_multiple_entry& i_entry(rm[start + i]); + + if (i_entry.file_offset > last_offset) + { + size_t skip = i_entry.file_offset - last_offset; + gold_assert(skip <= sizeof discard); + + iov[iov_index].iov_base = discard; + iov[iov_index].iov_len = skip; + ++iov_index; + + want += skip; + } + + iov[iov_index].iov_base = i_entry.buffer; + iov[iov_index].iov_len = i_entry.size; + ++iov_index; + + want += i_entry.size; + + last_offset = i_entry.file_offset + i_entry.size; + } + + gold_assert(iov_index < sizeof iov / sizeof iov[0]); + + if (::lseek(this->descriptor_, base + first_offset, SEEK_SET) < 0) + gold_fatal(_("%s: lseek failed: %s"), + this->filename().c_str(), strerror(errno)); + + ssize_t got = ::readv(this->descriptor_, iov, iov_index); + + if (got < 0) + gold_fatal(_("%s: readv failed: %s"), + this->filename().c_str(), strerror(errno)); + if (got != want) + gold_fatal(_("%s: file too short: read only %zd of %zd bytes at %lld"), + this->filename().c_str(), + got, want, static_cast(base + first_offset)); +} + +// Read several pieces of data from the file. + +void +File_read::read_multiple(off_t base, const Read_multiple& rm) +{ + size_t count = rm.size(); + size_t i = 0; + while (i < count) + { + // Find up to MAX_READV_ENTRIES consecutive entries which are + // less than one page apart. + const Read_multiple_entry& i_entry(rm[i]); + off_t i_off = i_entry.file_offset; + off_t end_off = i_off + i_entry.size; + size_t j; + for (j = i + 1; j < count; ++j) + { + if (j - i >= File_read::max_readv_entries) + break; + const Read_multiple_entry& j_entry(rm[j]); + off_t j_off = j_entry.file_offset; + gold_assert(j_off >= end_off); + off_t j_end_off = j_off + j_entry.size; + if (j_end_off - end_off >= File_read::page_size) + break; + end_off = j_end_off; + } + + if (j == i + 1) + this->read(base + i_off, i_entry.size, i_entry.buffer); + else + { + File_read::View* view = this->find_view(base + i_off, + end_off - i_off); + if (view == NULL) + this->do_readv(base, rm, i, j - i); + else + { + const unsigned char* v = (view->data() + + (base + i_off - view->start())); + for (size_t k = i; k < j; ++k) + { + const Read_multiple_entry& k_entry(rm[k]); + gold_assert(k_entry.file_offset - i_off + k_entry.size + <= end_off - i_off); + memcpy(k_entry.buffer, + v + (k_entry.file_offset - i_off), + k_entry.size); + } + } + } + + i = j; + } +} + +// Mark all views as no longer cached. + +void +File_read::clear_view_cache_marks() +{ + // Just ignore this if there are multiple objects associated with + // the file. Otherwise we will wind up uncaching and freeing some + // views for other objects. + if (this->object_count_ > 1) + return; + + for (Views::iterator p = this->views_.begin(); + p != this->views_.end(); + ++p) + p->second->clear_cache(); + for (Saved_views::iterator p = this->saved_views_.begin(); + p != this->saved_views_.end(); + ++p) + (*p)->clear_cache(); +} + +// Remove all the file views. For a file which has multiple +// associated objects (i.e., an archive), we keep accessed views +// around until next time, in the hopes that they will be useful for +// the next object. void File_read::clear_views(bool destroying) @@ -348,8 +499,19 @@ File_read::clear_views(bool destroying) Views::iterator p = this->views_.begin(); while (p != this->views_.end()) { - if (!p->second->is_locked() - && (destroying || !p->second->should_cache())) + bool should_delete; + if (p->second->is_locked()) + should_delete = false; + else if (destroying) + should_delete = true; + else if (p->second->should_cache()) + should_delete = false; + else if (this->object_count_ > 1 && p->second->accessed()) + should_delete = false; + else + should_delete = true; + + if (should_delete) { delete p->second; @@ -362,6 +524,7 @@ File_read::clear_views(bool destroying) else { gold_assert(!destroying); + p->second->clear_accessed(); ++p; } } @@ -369,8 +532,7 @@ File_read::clear_views(bool destroying) Saved_views::iterator q = this->saved_views_.begin(); while (q != this->saved_views_.end()) { - if (!(*q)->is_locked() - && (destroying || !(*q)->should_cache())) + if (!(*q)->is_locked()) { delete *q; q = this->saved_views_.erase(q); diff --git a/gold/fileread.h b/gold/fileread.h index 1c47f24..428c2f0 100644 --- a/gold/fileread.h +++ b/gold/fileread.h @@ -46,8 +46,9 @@ class File_read { public: File_read() - : name_(), descriptor_(-1), size_(0), token_(false), views_(), - saved_views_(), contents_(NULL), mapped_bytes_(0), released_(true) + : name_(), descriptor_(-1), object_count_(0), size_(0), token_(false), + views_(), saved_views_(), contents_(NULL), mapped_bytes_(0), + released_(true) { } ~File_read(); @@ -68,6 +69,16 @@ class File_read filename() const { return this->name_; } + // Add an object associated with a file. + void + add_object() + { ++this->object_count_; } + + // Remove an object associated with a file. + void + remove_object() + { --this->object_count_; } + // Lock the file for exclusive access within a particular Task::run // execution. This means that the descriptor can not be closed. // This routine may only be called when the workqueue lock is held. @@ -126,6 +137,34 @@ class File_read File_view* get_lasting_view(off_t start, section_size_type size, bool cache); + // Mark all views as no longer cached. + void + clear_view_cache_marks(); + + // A struct used to do a multiple read. + struct Read_multiple_entry + { + // The file offset of the data to read. + off_t file_offset; + // The amount of data to read. + section_size_type size; + // The buffer where the data should be placed. + unsigned char* buffer; + + Read_multiple_entry(off_t o, section_size_type s, unsigned char* b) + : file_offset(o), size(s), buffer(b) + { } + }; + + typedef std::vector Read_multiple; + + // Read a bunch of data from the file into various different + // locations. The vector must be sorted by ascending file_offset. + // BASE is a base offset to be added to all the offsets in the + // vector. + void + read_multiple(off_t base, const Read_multiple&); + // Dump statistical information to stderr. static void print_stats(); @@ -154,7 +193,7 @@ class File_read View(off_t start, section_size_type size, const unsigned char* data, bool cache, bool mapped) : start_(start), size_(size), data_(data), lock_count_(0), - cache_(cache), mapped_(mapped) + cache_(cache), mapped_(mapped), accessed_(true) { } ~View(); @@ -184,10 +223,26 @@ class File_read set_cache() { this->cache_ = true; } + void + clear_cache() + { this->cache_ = false; } + bool should_cache() const { return this->cache_; } + void + set_accessed() + { this->accessed_ = true; } + + void + clear_accessed() + { this->accessed_= false; } + + bool + accessed() const + { return this->accessed_; } + private: View(const View&); View& operator=(const View&); @@ -198,6 +253,7 @@ class File_read int lock_count_; bool cache_; bool mapped_; + bool accessed_; }; friend class View; @@ -238,10 +294,20 @@ class File_read // A simple list of Views. typedef std::list Saved_views; + // The maximum number of entries we will pass to ::readv. + static const size_t max_readv_entries = 128; + + // Use readv to read data. + void + do_readv(off_t base, const Read_multiple&, size_t start, size_t count); + // File name. std::string name_; // File descriptor. int descriptor_; + // The number of objects associated with this file. This will be + // more than 1 in the case of an archive. + int object_count_; // File size. off_t size_; // A token used to lock the file. diff --git a/gold/layout.cc b/gold/layout.cc index 3897ec7..eebb26c 100644 --- a/gold/layout.cc +++ b/gold/layout.cc @@ -739,7 +739,7 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab, off = this->set_section_offsets(off, BEFORE_INPUT_SECTIONS_PASS); // Create the symbol table sections. - this->create_symtab_sections(input_objects, symtab, task, &off); + this->create_symtab_sections(input_objects, symtab, &off); if (!parameters->doing_static_link()) this->assign_local_dynsym_offsets(input_objects); @@ -1212,7 +1212,6 @@ Layout::count_local_symbols(const Task* task, void Layout::create_symtab_sections(const Input_objects* input_objects, Symbol_table* symtab, - const Task* task, off_t* poff) { int symsize; @@ -1286,7 +1285,7 @@ Layout::create_symtab_sections(const Input_objects* input_objects, == this->dynsym_section_->data_size() - locsize); } - off = symtab->finalize(task, local_symcount, off, dynoff, dyn_global_index, + off = symtab->finalize(local_symcount, off, dynoff, dyn_global_index, dyncount, &this->sympool_); if (!parameters->strip_all()) diff --git a/gold/layout.h b/gold/layout.h index 3084d60..131d6a6 100644 --- a/gold/layout.h +++ b/gold/layout.h @@ -292,8 +292,7 @@ class Layout // Create the output sections for the symbol table. void - create_symtab_sections(const Input_objects*, Symbol_table*, const Task*, - off_t*); + create_symtab_sections(const Input_objects*, Symbol_table*, off_t*); // Create the .shstrtab section. Output_section* diff --git a/gold/object.cc b/gold/object.cc index 1a0d064..e56f6a4 100644 --- a/gold/object.cc +++ b/gold/object.cc @@ -125,7 +125,17 @@ Object::handle_gnu_warning_section(const char* name, unsigned int shndx, const int warn_prefix_len = sizeof warn_prefix - 1; if (strncmp(name, warn_prefix, warn_prefix_len) == 0) { - symtab->add_warning(name + warn_prefix_len, this, shndx); + // Read the section contents to get the warning text. It would + // be nicer if we only did this if we have to actually issue a + // warning. Unfortunately, warnings are issued as we relocate + // sections. That means that we can not lock the object then, + // as we might try to issue the same warning multiple times + // simultaneously. + section_size_type len; + const unsigned char* contents = this->section_contents(shndx, &len, + false); + std::string warning(reinterpret_cast(contents), len); + symtab->add_warning(name + warn_prefix_len, this, warning); return true; } return false; @@ -404,7 +414,7 @@ Sized_relobj::include_section_group( return false; } off_t symoff = symshdr.get_sh_offset() + shdr.get_sh_info() * This::sym_size; - const unsigned char* psym = this->get_view(symoff, This::sym_size, true); + const unsigned char* psym = this->get_view(symoff, This::sym_size, false); elfcpp::Sym sym(psym); // Read the symbol table names. @@ -729,10 +739,11 @@ Sized_relobj::do_add_symbols(Symbol_table* symtab, sd->symbol_names = NULL; } -// Finalize the local symbols. Here we add their names to *POOL and -// *DYNPOOL, and we add their values to THIS->LOCAL_VALUES_. This -// function is always called from a singleton thread. The actual -// output of the local symbols will occur in a separate task. +// First pass over the local symbols. Here we add their names to +// *POOL and *DYNPOOL, and we store the symbol value in +// THIS->LOCAL_VALUES_. This function is always called from a +// singleton thread. This is followed by a call to +// finalize_local_symbols. template void @@ -833,7 +844,7 @@ Sized_relobj::do_count_local_symbols(Stringpool* pool, this->output_local_dynsym_count_ = dyncount; } -// Finalize the local symbols. Here we add their values to +// Finalize the local symbols. Here we set the final value in // THIS->LOCAL_VALUES_ and set their output symbol table indexes. // This function is always called from a singleton thread. The actual // output of the local symbols will occur in a separate task. @@ -1008,7 +1019,7 @@ Sized_relobj::write_local_symbols( section_size_type strtab_size; const unsigned char* pnamesu = this->section_contents(strtab_shndx, &strtab_size, - true); + false); const char* pnames = reinterpret_cast(pnamesu); // Get views into the output file for the portions of the symbol table diff --git a/gold/object.h b/gold/object.h index f5e4ab6..e4140be 100644 --- a/gold/object.h +++ b/gold/object.h @@ -139,10 +139,10 @@ class Object off_t offset = 0) : name_(name), input_file_(input_file), offset_(offset), shnum_(-1U), is_dynamic_(is_dynamic), target_(NULL) - { } + { input_file->file().add_object(); } virtual ~Object() - { } + { this->input_file_->file().remove_object(); } // Return the name of the object as we would report it to the tuser. const std::string& @@ -294,6 +294,37 @@ class Object View view(Location loc) { return View(this->get_view(loc.file_offset, loc.data_size, true)); } + // Get a view into the underlying file. + const unsigned char* + get_view(off_t start, section_size_type size, bool cache) + { + return this->input_file()->file().get_view(start + this->offset_, size, + cache); + } + + // Get a lasting view into the underlying file. + File_view* + get_lasting_view(off_t start, section_size_type size, bool cache) + { + return this->input_file()->file().get_lasting_view(start + this->offset_, + size, cache); + } + + // Read data from the underlying file. + void + read(off_t start, section_size_type size, void* p) const + { this->input_file()->file().read(start + this->offset_, size, p); } + + // Read multiple data from the underlying file. + void + read_multiple(const File_read::Read_multiple& rm) + { this->input_file()->file().read_multiple(this->offset_, rm); } + + // Stop caching views in the underlying file. + void + clear_view_cache_marks() + { this->input_file()->file().clear_view_cache_marks(); } + protected: // Read the symbols--implemented by child class. virtual void @@ -342,27 +373,6 @@ class Object input_file() const { return this->input_file_; } - // Get a view into the underlying file. - const unsigned char* - get_view(off_t start, section_size_type size, bool cache) - { - return this->input_file()->file().get_view(start + this->offset_, size, - cache); - } - - // Get a lasting view into the underlying file. - File_view* - get_lasting_view(off_t start, section_size_type size, bool cache) - { - return this->input_file()->file().get_lasting_view(start + this->offset_, - size, cache); - } - - // Read data from the underlying file. - void - read(off_t start, section_size_type size, void* p) const - { this->input_file()->file().read(start + this->offset_, size, p); } - // Set the target. void set_target(int machine, int size, bool big_endian, int osabi, @@ -1206,7 +1216,7 @@ class Sized_relobj : public Relobj // Write section data to the output file. Record the views and // sizes in VIEWS for use when relocating. void - write_sections(const unsigned char* pshdrs, Output_file*, Views*) const; + write_sections(const unsigned char* pshdrs, Output_file*, Views*); // Relocate the sections in the output file. void @@ -1229,6 +1239,15 @@ class Sized_relobj : public Relobj const Stringpool_template*, const Stringpool_template*); + // Clear the local symbol information. + void + clear_local_symbols() + { + this->local_values_.clear(); + this->local_got_offsets_.clear(); + this->local_tls_got_offsets_.clear(); + } + // The GOT offsets of local symbols. This map also stores GOT offsets // for tp-relative offsets for TLS symbols. typedef Unordered_map Local_got_offsets; diff --git a/gold/reloc.cc b/gold/reloc.cc index f88151f..d361f16 100644 --- a/gold/reloc.cc +++ b/gold/reloc.cc @@ -22,6 +22,8 @@ #include "gold.h" +#include + #include "workqueue.h" #include "symtab.h" #include "output.h" @@ -159,6 +161,11 @@ Relocate_task::run(Workqueue*) { this->object_->relocate(this->options_, this->symtab_, this->layout_, this->of_); + + // This is normally the last thing we will do with an object, so + // uncache all views. + this->object_->clear_view_cache_marks(); + this->object_->release(); } @@ -376,8 +383,20 @@ Sized_relobj::do_relocate(const General_options& options, // Write out the local symbols. this->write_local_symbols(of, layout->sympool(), layout->dynpool()); + + // We should no longer need the local symbol values. + this->clear_local_symbols(); } +// Sort a Read_multiple vector by file offset. +struct Read_multiple_compare +{ + inline bool + operator()(const File_read::Read_multiple_entry& rme1, + const File_read::Read_multiple_entry& rme2) const + { return rme1.file_offset < rme2.file_offset; } +}; + // Write section data to the output file. PSHDRS points to the // section headers. Record the views in *PVIEWS for use when // relocating. @@ -386,11 +405,14 @@ template void Sized_relobj::write_sections(const unsigned char* pshdrs, Output_file* of, - Views* pviews) const + Views* pviews) { unsigned int shnum = this->shnum(); const std::vector& map_sections(this->map_to_output()); + File_read::Read_multiple rm; + bool is_sorted = true; + const unsigned char* p = pshdrs + This::shdr_size; for (unsigned int i = 1; i < shnum; ++i, p += This::shdr_size) { @@ -468,7 +490,13 @@ Sized_relobj::write_sections(const unsigned char* pshdrs, unsigned char* buffer = os->postprocessing_buffer(); view = buffer + view_start; if (output_offset != -1) - this->read(shdr.get_sh_offset(), view_size, view); + { + off_t sh_offset = shdr.get_sh_offset(); + if (!rm.empty() && rm.back().file_offset > sh_offset) + is_sorted = false; + rm.push_back(File_read::Read_multiple_entry(sh_offset, + view_size, view)); + } } else { @@ -477,7 +505,11 @@ Sized_relobj::write_sections(const unsigned char* pshdrs, else { view = of->get_output_view(view_start, view_size); - this->read(shdr.get_sh_offset(), view_size, view); + off_t sh_offset = shdr.get_sh_offset(); + if (!rm.empty() && rm.back().file_offset > sh_offset) + is_sorted = false; + rm.push_back(File_read::Read_multiple_entry(sh_offset, + view_size, view)); } } @@ -490,6 +522,14 @@ Sized_relobj::write_sections(const unsigned char* pshdrs, pvs->is_input_output_view = output_offset == -1; pvs->is_postprocessing_view = os->requires_postprocessing(); } + + // Actually read the data. + if (!rm.empty()) + { + if (!is_sorted) + std::sort(rm.begin(), rm.end(), Read_multiple_compare()); + this->read_multiple(rm); + } } // Relocate section data. VIEWS points to the section data as views diff --git a/gold/symtab.cc b/gold/symtab.cc index 4a1c5ee..a9f5138 100644 --- a/gold/symtab.cc +++ b/gold/symtab.cc @@ -1403,8 +1403,8 @@ Symbol_table::set_dynsym_indexes(const Target* target, // OFF. Add their names to POOL. Return the new file offset. off_t -Symbol_table::finalize(const Task* task, unsigned int index, off_t off, - off_t dynoff, size_t dyn_global_index, size_t dyncount, +Symbol_table::finalize(unsigned int index, off_t off, off_t dynoff, + size_t dyn_global_index, size_t dyncount, Stringpool* pool) { off_t ret; @@ -1437,7 +1437,7 @@ Symbol_table::finalize(const Task* task, unsigned int index, off_t off, // Now that we have the final symbol table, we can reliably note // which symbols should get warnings. - this->warnings_.note_warnings(this, task); + this->warnings_.note_warnings(this); return ret; } @@ -2004,10 +2004,10 @@ Symbol_table::detect_odr_violations(const Task* task, void Warnings::add_warning(Symbol_table* symtab, const char* name, Object* obj, - unsigned int shndx) + const std::string& warning) { name = symtab->canonicalize_name(name); - this->warnings_[name].set(obj, shndx); + this->warnings_[name].set(obj, warning); } // Look through the warnings and mark the symbols for which we should @@ -2015,7 +2015,7 @@ Warnings::add_warning(Symbol_table* symtab, const char* name, Object* obj, // sources for all the symbols. void -Warnings::note_warnings(Symbol_table* symtab, const Task* task) +Warnings::note_warnings(Symbol_table* symtab) { for (Warning_table::iterator p = this->warnings_.begin(); p != this->warnings_.end(); @@ -2025,24 +2025,7 @@ Warnings::note_warnings(Symbol_table* symtab, const Task* task) if (sym != NULL && sym->source() == Symbol::FROM_OBJECT && sym->object() == p->second.object) - { - sym->set_has_warning(); - - // Read the section contents to get the warning text. It - // would be nicer if we only did this if we have to actually - // issue a warning. Unfortunately, warnings are issued as - // we relocate sections. That means that we can not lock - // the object then, as we might try to issue the same - // warning multiple times simultaneously. - { - Task_lock_obj tl(task, p->second.object); - const unsigned char* c; - section_size_type len; - c = p->second.object->section_contents(p->second.shndx, &len, - false); - p->second.set_text(reinterpret_cast(c), len); - } - } + sym->set_has_warning(); } } diff --git a/gold/symtab.h b/gold/symtab.h index 786e5cb..59cda2e 100644 --- a/gold/symtab.h +++ b/gold/symtab.h @@ -897,15 +897,16 @@ class Warnings : warnings_() { } - // Add a warning for symbol NAME in section SHNDX in object OBJ. + // Add a warning for symbol NAME in object OBJ. WARNING is the text + // of the warning. void add_warning(Symbol_table* symtab, const char* name, Object* obj, - unsigned int shndx); + const std::string& warning); // For each symbol for which we should give a warning, make a note // on the symbol. void - note_warnings(Symbol_table* symtab, const Task*); + note_warnings(Symbol_table* symtab); // Issue a warning for a reference to SYM at RELINFO's location. template @@ -922,25 +923,19 @@ class Warnings { // The object the warning is in. Object* object; - // The index of the warning section. - unsigned int shndx; - // The warning text if we have already loaded it. + // The warning text. std::string text; Warning_location() - : object(NULL), shndx(0), text() + : object(NULL), text() { } void - set(Object* o, unsigned int s) + set(Object* o, const std::string& t) { this->object = o; - this->shndx = s; + this->text = t; } - - void - set_text(const char* t, section_size_type l) - { this->text.assign(t, l); } }; // A mapping from warning symbol names (canonicalized in @@ -1057,10 +1052,11 @@ class Symbol_table void allocate_commons(const General_options&, Layout*); - // Add a warning for symbol NAME in section SHNDX in object OBJ. + // Add a warning for symbol NAME in object OBJ. WARNING is the text + // of the warning. void - add_warning(const char* name, Object* obj, unsigned int shndx) - { this->warnings_.add_warning(this, name, obj, shndx); } + add_warning(const char* name, Object* obj, const std::string& warning) + { this->warnings_.add_warning(this, name, obj, warning); } // Canonicalize a symbol name for use in the hash table. const char* @@ -1103,7 +1099,7 @@ class Symbol_table // symbol, and DYNCOUNT is the number of global dynamic symbols. // This records the parameters, and returns the new file offset. off_t - finalize(const Task*, unsigned int index, off_t off, off_t dynoff, + finalize(unsigned int index, off_t off, off_t dynoff, size_t dyn_global_index, size_t dyncount, Stringpool* pool); // Write out the global symbols. -- cgit v1.1