Reduce the number of system calls. Use readv instead of pread. Do

better handling of cached views.
This commit is contained in:
Ian Lance Taylor 2008-01-02 23:48:49 +00:00
parent 2745d86e69
commit cb29561284
12 changed files with 404 additions and 120 deletions

View File

@ -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));

View File

@ -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.

View File

@ -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

View File

@ -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);

View File

@ -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.

View File

@ -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())

View File

@ -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*

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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();
}
}

View File

@ -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.