+ return new File_view(*this, pv,
+ (pv->data()
+ + (offset + start - pv->start() + pv->byteshift())));
+}
+
+// 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;
+ }
+
+ this->reopen_descriptor();
+
+ 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<long long>(base + first_offset));
+}
+
+// Portable IOV_MAX.
+
+#if !defined(HAVE_READV)
+#define GOLD_IOV_MAX 1
+#elif defined(IOV_MAX)
+#define GOLD_IOV_MAX IOV_MAX
+#else
+#define GOLD_IOV_MAX (File_read::max_readv_entries * 2)
+#endif
+
+// Read several pieces of data from the file.
+
+void
+File_read::read_multiple(off_t base, const Read_multiple& rm)
+{
+ static size_t iov_max = GOLD_IOV_MAX;
+ 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 || j - i >= iov_max / 2)
+ 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,
+ -1U, NULL);
+ if (view == NULL)
+ this->do_readv(base, rm, i, j - i);
+ else
+ {
+ const unsigned char* v = (view->data()
+ + (base + i_off - view->start()
+ + view->byteshift()));
+ for (size_t k = i; k < j; ++k)
+ {
+ const Read_multiple_entry& k_entry(rm[k]);
+ gold_assert((convert_to_section_size_type(k_entry.file_offset
+ - i_off)
+ + k_entry.size)
+ <= convert_to_section_size_type(end_off
+ - i_off));
+ memcpy(k_entry.buffer,
+ v + (k_entry.file_offset - i_off),
+ k_entry.size);
+ }
+ }
+ }
+
+ i = j;
+ }