X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=gold%2Ffileread.cc;h=1bbd8412a8109cf1e6c051dd0311a50d133b25b9;hb=ad2d6943a49fa11ba1e23749973c75feb12dcf6b;hp=a39d530ab8753ed65b567a3405e0e9b32eb5da63;hpb=ba45d2478b259454e5b4c2d7dcaa7a35ecbf329c;p=binutils-gdb.git diff --git a/gold/fileread.cc b/gold/fileread.cc index a39d530ab87..1bbd8412a81 100644 --- a/gold/fileread.cc +++ b/gold/fileread.cc @@ -26,6 +26,8 @@ #include #include #include +#include +#include "filenames.h" #include "options.h" #include "dirsearch.h" @@ -39,7 +41,14 @@ namespace gold File_read::View::~View() { gold_assert(!this->is_locked()); - delete[] this->data_; + if (!this->mapped_) + delete[] this->data_; + else + { + if (::munmap(const_cast(this->data_), this->size_) != 0) + fprintf(stderr, _("%s: munmap failed: %s\n"), + program_name, strerror(errno)); + } } void @@ -89,8 +98,23 @@ File_read::open(const std::string& name) && this->descriptor_ < 0 && this->name_.empty()); this->name_ = name; + this->descriptor_ = ::open(this->name_.c_str(), O_RDONLY); + + if (this->descriptor_ >= 0) + { + struct stat s; + if (::fstat(this->descriptor_, &s) < 0) + { + fprintf(stderr, _("%s: %s: fstat failed: %s"), program_name, + this->name_.c_str(), strerror(errno)); + gold_exit(false); + } + this->size_ = s.st_size; + } + ++this->lock_count_; + return this->descriptor_ >= 0; } @@ -98,14 +122,14 @@ File_read::open(const std::string& name) bool File_read::open(const std::string& name, const unsigned char* contents, - off_t contents_size) + off_t size) { gold_assert(this->lock_count_ == 0 && this->descriptor_ < 0 && this->name_.empty()); this->name_ = name; this->contents_ = contents; - this->contents_size_ = contents_size; + this->size_ = size; ++this->lock_count_; return true; } @@ -121,6 +145,8 @@ File_read::unlock() { gold_assert(this->lock_count_ > 0); --this->lock_count_; + if (this->lock_count_ == 0) + this->clear_views(false); } bool @@ -144,62 +170,45 @@ File_read::find_view(off_t start, off_t size) return p->second; } -// Read data from the file. Return the number of bytes read. If -// PBYTES is not NULL, store the number of bytes in *PBYTES, otherwise -// require that we read exactly the number of bytes requested. +// Read SIZE bytes from the file starting at offset START. Read into +// the buffer at P. -off_t -File_read::do_read(off_t start, off_t size, void* p, off_t* pbytes) +void +File_read::do_read(off_t start, off_t size, void* p) { gold_assert(this->lock_count_ > 0); off_t bytes; - if (this->contents_ == NULL) + if (this->contents_ != NULL) { - int o = this->descriptor_; - - if (lseek(o, start, SEEK_SET) < 0) + bytes = this->size_ - start; + if (bytes >= size) { - fprintf(stderr, _("%s: %s: lseek to %lld failed: %s"), - program_name, this->filename().c_str(), - static_cast(start), - strerror(errno)); - gold_exit(false); + memcpy(p, this->contents_ + start, size); + return; } + } + else + { + bytes = ::pread(this->descriptor_, p, size, start); + if (bytes == size) + return; - bytes = ::read(o, p, size); if (bytes < 0) { - fprintf(stderr, _("%s: %s: read failed: %s\n"), + fprintf(stderr, _("%s: %s: pread failed: %s\n"), program_name, this->filename().c_str(), strerror(errno)); gold_exit(false); } } - else - { - bytes = this->contents_size_ - start; - if (bytes < 0) - bytes = 0; - else if (bytes > size) - bytes = size; - memcpy(p, this->contents_ + start, bytes); - } - if (pbytes != NULL) - *pbytes = bytes; - else if (bytes != size) - { - fprintf(stderr, - _("%s: %s: file too short: read only %lld of %lld " - "bytes at %lld\n"), - program_name, this->filename().c_str(), - static_cast(bytes), - static_cast(size), - static_cast(start)); - gold_exit(false); - } - - return bytes; + fprintf(stderr, + _("%s: %s: file too short: read only %lld of %lld bytes at %lld\n"), + program_name, this->filename().c_str(), + static_cast(bytes), + static_cast(size), + static_cast(start)); + gold_exit(false); } // Read data from the file. @@ -216,30 +225,13 @@ File_read::read(off_t start, off_t size, void* p) return; } - this->do_read(start, size, p, NULL); -} - -void -File_read::read_up_to(off_t start, off_t size, void* p, off_t* pbytes) -{ - gold_assert(this->lock_count_ > 0); - - File_read::View* pv = this->find_view(start, size); - if (pv != NULL) - { - memcpy(p, pv->data() + (start - pv->start()), size); - if (pbytes != NULL) - *pbytes = size; - return; - } - - this->do_read(start, size, p, pbytes); + this->do_read(start, size, p); } // Find an existing view or make a new one. File_read::View* -File_read::find_or_make_view(off_t start, off_t size, off_t* pbytes) +File_read::find_or_make_view(off_t start, off_t size, bool cache) { gold_assert(this->lock_count_ > 0); @@ -255,8 +247,8 @@ File_read::find_or_make_view(off_t start, off_t size, off_t* pbytes) File_read::View* v = ins.first->second; if (v->size() - (start - v->start()) >= size) { - if (pbytes != NULL) - *pbytes = size; + if (cache) + v->set_cache(); return v; } @@ -264,38 +256,45 @@ File_read::find_or_make_view(off_t start, off_t size, off_t* pbytes) this->saved_views_.push_back(v); } - // We need to read data from the file. + // We need to read data from the file. We read full pages for + // greater efficiency on small files. off_t psize = File_read::pages(size + (start - poff)); - unsigned char* p = new unsigned char[psize]; - off_t got_bytes; - off_t bytes = this->do_read(poff, psize, p, &got_bytes); + if (poff + psize >= this->size_) + { + psize = this->size_ - poff; + gold_assert(psize >= size); + } - File_read::View* v = new File_read::View(poff, bytes, p); + File_read::View* v; - ins.first->second = v; - - if (bytes - (start - poff) >= size) + if (this->contents_ != NULL) { - if (pbytes != NULL) - *pbytes = size; - return v; + unsigned char* p = new unsigned char[psize]; + this->do_read(poff, psize, p); + v = new File_read::View(poff, psize, p, cache, false); } - - if (pbytes != NULL) + else { - *pbytes = bytes - (start - poff); - return v; + void* p = ::mmap(NULL, psize, PROT_READ, MAP_SHARED, + this->descriptor_, poff); + if (p == MAP_FAILED) + { + fprintf(stderr, _("%s: %s: mmap offset %lld size %lld failed: %s\n"), + program_name, this->filename().c_str(), + static_cast(poff), + static_cast(psize), + strerror(errno)); + gold_exit(false); + } + + const unsigned char* pbytes = static_cast(p); + v = new File_read::View(poff, psize, pbytes, cache, true); } - fprintf(stderr, - _("%s: %s: file too short: read only %lld of %lld bytes at %lld\n"), - program_name, this->filename().c_str(), - static_cast(bytes - (start - poff)), - static_cast(size), - static_cast(start)); - gold_exit(false); + ins.first->second = v; + return v; } // This implementation of get_view just reads into a memory buffer, @@ -303,26 +302,18 @@ File_read::find_or_make_view(off_t start, off_t size, off_t* pbytes) // mmap. const unsigned char* -File_read::get_view(off_t start, off_t size) -{ - gold_assert(this->lock_count_ > 0); - File_read::View* pv = this->find_or_make_view(start, size, NULL); - return pv->data() + (start - pv->start()); -} - -const unsigned char* -File_read::get_view_and_size(off_t start, off_t size, off_t* pbytes) +File_read::get_view(off_t start, off_t size, bool cache) { gold_assert(this->lock_count_ > 0); - File_read::View* pv = this->find_or_make_view(start, size, pbytes); + File_read::View* pv = this->find_or_make_view(start, size, cache); return pv->data() + (start - pv->start()); } File_view* -File_read::get_lasting_view(off_t start, off_t size) +File_read::get_lasting_view(off_t start, off_t size, bool cache) { gold_assert(this->lock_count_ > 0); - File_read::View* pv = this->find_or_make_view(start, size, NULL); + File_read::View* pv = this->find_or_make_view(start, size, cache); pv->lock(); return new File_view(*this, pv, pv->data() + (start - pv->start())); } @@ -336,7 +327,8 @@ File_read::clear_views(bool destroying) p != this->views_.end(); ++p) { - if (!p->second->is_locked()) + if (!p->second->is_locked() + && (destroying || !p->second->should_cache())) delete p->second; else { @@ -349,7 +341,8 @@ File_read::clear_views(bool destroying) Saved_views::iterator p = this->saved_views_.begin(); while (p != this->saved_views_.end()) { - if (!(*p)->is_locked()) + if (!(*p)->is_locked() + && (destroying || !(*p)->should_cache())) { delete *p; p = this->saved_views_.erase(p); @@ -379,21 +372,38 @@ Input_file::Input_file(const char* name, const unsigned char* contents, : file_() { this->input_argument_ = - new Input_file_argument(name, false, Position_dependent_options()); + new Input_file_argument(name, false, "", Position_dependent_options()); bool ok = file_.open(name, contents, size); gold_assert(ok); } // Open the file. +// If the filename is not absolute, we assume it is in the current +// directory *except* when: +// A) input_argument_->is_lib() is true; or +// B) input_argument_->extra_search_path() is not empty. +// In both cases, we look in extra_search_path + library_path to find +// the file location, rather than the current directory. + void Input_file::open(const General_options& options, const Dirsearch& dirpath) { std::string name; - if (!this->input_argument_->is_lib()) + + // Case 1: name is an absolute file, just try to open it + // Case 2: name is relative but is_lib is false and extra_search_path + // is empty + if (IS_ABSOLUTE_PATH (this->input_argument_->name()) + || (!this->input_argument_->is_lib() + && this->input_argument_->extra_search_path() == NULL)) name = this->input_argument_->name(); - else + + // Case 3: is_lib is true + else if (this->input_argument_->is_lib()) { + // We don't yet support extra_search_path with -l. + gold_assert(this->input_argument_->extra_search_path() == NULL); std::string n1("lib"); n1 += this->input_argument_->name(); std::string n2; @@ -404,15 +414,41 @@ Input_file::open(const General_options& options, const Dirsearch& dirpath) n2 = n1 + ".a"; n1 += ".so"; } - name = dirpath.find(n1, n2); + name = dirpath.find(n1, n2, &this->is_in_sysroot_); if (name.empty()) { - fprintf(stderr, _("%s: cannot find %s\n"), program_name, + fprintf(stderr, _("%s: cannot find -l%s\n"), program_name, this->input_argument_->name()); gold_exit(false); } } + // Case 4: extra_search_path is not empty + else + { + gold_assert(this->input_argument_->extra_search_path() != NULL); + + // First, check extra_search_path. + name = this->input_argument_->extra_search_path(); + if (!IS_DIR_SEPARATOR (name[name.length() - 1])) + name += '/'; + name += this->input_argument_->name(); + struct stat dummy_stat; + if (::stat(name.c_str(), &dummy_stat) < 0) + { + // extra_search_path failed, so check the normal search-path. + name = dirpath.find(this->input_argument_->name(), "", + &this->is_in_sysroot_); + if (name.empty()) + { + fprintf(stderr, _("%s: cannot find %s\n"), program_name, + this->input_argument_->name()); + gold_exit(false); + } + } + } + + // Now that we've figured out where the file lives, try to open it. if (!this->file_.open(name)) { fprintf(stderr, _("%s: cannot open %s: %s\n"), program_name,