aboutsummaryrefslogtreecommitdiff
path: root/gold
diff options
context:
space:
mode:
Diffstat (limited to 'gold')
-rw-r--r--gold/archive.cc18
-rw-r--r--gold/archive.h7
-rw-r--r--gold/dynobj.cc6
-rw-r--r--gold/fileread.cc212
-rw-r--r--gold/fileread.h72
-rw-r--r--gold/layout.cc5
-rw-r--r--gold/layout.h3
-rw-r--r--gold/object.cc27
-rw-r--r--gold/object.h67
-rw-r--r--gold/reloc.cc46
-rw-r--r--gold/symtab.cc31
-rw-r--r--gold/symtab.h30
12 files changed, 404 insertions, 120 deletions
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<const char*>(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<const Archive_header*>(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<off_t>(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<size, big_endian>::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<size, big_endian>::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 <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
+#include <sys/uio.h>
#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<off_t>(p->second->size())
+ < start + static_cast<off_t>(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<long long>(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_entry> 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<View*> 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<const char*>(contents), len);
+ symtab->add_warning(name + warn_prefix_len, this, warning);
return true;
}
return false;
@@ -404,7 +414,7 @@ Sized_relobj<size, big_endian>::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<size, big_endian> sym(psym);
// Read the symbol table names.
@@ -729,10 +739,11 @@ Sized_relobj<size, big_endian>::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<int size, bool big_endian>
void
@@ -833,7 +844,7 @@ Sized_relobj<size, big_endian>::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<size, big_endian>::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<const char*>(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<char>*,
const Stringpool_template<char>*);
+ // 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<unsigned int, unsigned int> 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 <algorithm>
+
#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<size, big_endian>::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<int size, bool big_endian>
void
Sized_relobj<size, big_endian>::write_sections(const unsigned char* pshdrs,
Output_file* of,
- Views* pviews) const
+ Views* pviews)
{
unsigned int shnum = this->shnum();
const std::vector<Map_to_output>& 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<size, big_endian>::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<size, big_endian>::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<size, big_endian>::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<Object> 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<const char*>(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<int size, bool big_endian>
@@ -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.