mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-09-12 09:39:30 +08:00
Reduce the number of system calls. Use readv instead of pread. Do
better handling of cached views.
This commit is contained in:
@ -85,7 +85,8 @@ Archive::setup(Task* task)
|
|||||||
// The first member of the archive should be the symbol table.
|
// The first member of the archive should be the symbol table.
|
||||||
std::string armap_name;
|
std::string armap_name;
|
||||||
section_size_type armap_size =
|
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;
|
off_t off = sarmag;
|
||||||
if (armap_name.empty())
|
if (armap_name.empty())
|
||||||
{
|
{
|
||||||
@ -96,15 +97,18 @@ Archive::setup(Task* task)
|
|||||||
gold_error(_("%s: no archive symbol table (run ranlib)"),
|
gold_error(_("%s: no archive symbol table (run ranlib)"),
|
||||||
this->name().c_str());
|
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)
|
if ((off & 1) != 0)
|
||||||
++off;
|
++off;
|
||||||
std::string xname;
|
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 == "/")
|
if (xname == "/")
|
||||||
{
|
{
|
||||||
const unsigned char* p = this->get_view(off + sizeof(Archive_header),
|
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);
|
const char* px = reinterpret_cast<const char*>(p);
|
||||||
this->extended_names_.assign(px, extended_size);
|
this->extended_names_.assign(px, extended_size);
|
||||||
}
|
}
|
||||||
@ -157,9 +161,9 @@ Archive::read_armap(off_t start, section_size_type size)
|
|||||||
// of the member.
|
// of the member.
|
||||||
|
|
||||||
off_t
|
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);
|
const Archive_header* hdr = reinterpret_cast<const Archive_header*>(p);
|
||||||
return this->interpret_header(hdr, off, pname);
|
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)
|
Input_objects* input_objects, off_t off)
|
||||||
{
|
{
|
||||||
std::string n;
|
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));
|
const off_t memoff = off + static_cast<off_t>(sizeof(Archive_header));
|
||||||
|
|
||||||
|
@ -117,10 +117,11 @@ class Archive
|
|||||||
void
|
void
|
||||||
read_armap(off_t start, section_size_type size);
|
read_armap(off_t start, section_size_type size);
|
||||||
|
|
||||||
// Read an archive member header at OFF. Return the size of the
|
// Read an archive member header at OFF. CACHE is whether to cache
|
||||||
// member, and set *PNAME to the name.
|
// the file view. Return the size of the member, and set *PNAME to
|
||||||
|
// the name.
|
||||||
off_t
|
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
|
// Interpret an archive header HDR at OFF. Return the size of the
|
||||||
// member, and set *PNAME to the name.
|
// member, and set *PNAME to the name.
|
||||||
|
@ -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(),
|
sd->symbol_names = this->get_lasting_view(strtabshdr.get_sh_offset(),
|
||||||
strtabshdr.get_sh_size(),
|
strtabshdr.get_sh_size(),
|
||||||
true);
|
false);
|
||||||
sd->symbol_names_size =
|
sd->symbol_names_size =
|
||||||
convert_to_section_size_type(strtabshdr.get_sh_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;
|
delete sd->verneed;
|
||||||
sd->verneed = NULL;
|
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
|
// Given a vector of hash codes, compute the number of hash buckets to
|
||||||
|
210
gold/fileread.cc
210
gold/fileread.cc
@ -27,6 +27,7 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
#include "filenames.h"
|
#include "filenames.h"
|
||||||
|
|
||||||
#include "options.h"
|
#include "options.h"
|
||||||
@ -194,11 +195,21 @@ inline File_read::View*
|
|||||||
File_read::find_view(off_t start, section_size_type size) const
|
File_read::find_view(off_t start, section_size_type size) const
|
||||||
{
|
{
|
||||||
off_t page = File_read::page_offset(start);
|
off_t page = File_read::page_offset(start);
|
||||||
Views::const_iterator p = this->views_.find(page);
|
|
||||||
if (p == this->views_.end())
|
Views::const_iterator p = this->views_.lower_bound(page);
|
||||||
|
if (p == this->views_.end() || p->first > page)
|
||||||
|
{
|
||||||
|
if (p == this->views_.begin())
|
||||||
return NULL;
|
return NULL;
|
||||||
if (p->second->size() - (start - page) < size)
|
--p;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->second->start() + static_cast<off_t>(p->second->size())
|
||||||
|
< start + static_cast<off_t>(size))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
p->second->set_accessed();
|
||||||
|
|
||||||
return p->second;
|
return p->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,7 +255,7 @@ File_read::do_read(off_t start, section_size_type size, void* p) const
|
|||||||
void
|
void
|
||||||
File_read::read(off_t start, section_size_type size, void* p) const
|
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)
|
if (pv != NULL)
|
||||||
{
|
{
|
||||||
memcpy(p, pv->data() + (start - pv->start()), size);
|
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());
|
gold_assert(!this->token_.is_writable());
|
||||||
this->released_ = false;
|
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);
|
off_t poff = File_read::page_offset(start);
|
||||||
|
|
||||||
File_read::View* const vnull = NULL;
|
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)
|
if (!ins.second)
|
||||||
{
|
{
|
||||||
// There was an existing view at this offset.
|
// There was an existing view at this offset. It must not be
|
||||||
File_read::View* v = ins.first->second;
|
// large enough. We can't delete it here, since something might
|
||||||
if (v->size() - (start - v->start()) >= size)
|
// be using it; put it on a list to be deleted when the file is
|
||||||
{
|
// unlocked.
|
||||||
if (cache)
|
v = ins.first->second;
|
||||||
v->set_cache();
|
gold_assert(v->size() - (start - v->start()) < size);
|
||||||
return v;
|
if (v->should_cache())
|
||||||
}
|
cache = true;
|
||||||
|
v->clear_cache();
|
||||||
// This view is not large enough.
|
|
||||||
this->saved_views_.push_back(v);
|
this->saved_views_.push_back(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need to read data from the file. We read full pages for
|
// We need to map data from the file.
|
||||||
// greater efficiency on small files.
|
|
||||||
|
|
||||||
section_size_type psize = File_read::pages(size + (start - poff));
|
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);
|
gold_assert(psize >= size);
|
||||||
}
|
}
|
||||||
|
|
||||||
File_read::View* v;
|
|
||||||
|
|
||||||
if (this->contents_ != NULL)
|
if (this->contents_ != NULL)
|
||||||
{
|
{
|
||||||
unsigned char* p = new unsigned char[psize];
|
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
|
else
|
||||||
{
|
{
|
||||||
void* p = ::mmap(NULL, psize, PROT_READ, MAP_SHARED,
|
void* p = ::mmap(NULL, psize, PROT_READ, MAP_PRIVATE,
|
||||||
this->descriptor_, poff);
|
this->descriptor_, poff);
|
||||||
if (p == MAP_FAILED)
|
if (p == MAP_FAILED)
|
||||||
gold_fatal(_("%s: mmap offset %lld size %lld failed: %s"),
|
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()));
|
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
|
void
|
||||||
File_read::clear_views(bool destroying)
|
File_read::clear_views(bool destroying)
|
||||||
@ -348,8 +499,19 @@ File_read::clear_views(bool destroying)
|
|||||||
Views::iterator p = this->views_.begin();
|
Views::iterator p = this->views_.begin();
|
||||||
while (p != this->views_.end())
|
while (p != this->views_.end())
|
||||||
{
|
{
|
||||||
if (!p->second->is_locked()
|
bool should_delete;
|
||||||
&& (destroying || !p->second->should_cache()))
|
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;
|
delete p->second;
|
||||||
|
|
||||||
@ -362,6 +524,7 @@ File_read::clear_views(bool destroying)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
gold_assert(!destroying);
|
gold_assert(!destroying);
|
||||||
|
p->second->clear_accessed();
|
||||||
++p;
|
++p;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -369,8 +532,7 @@ File_read::clear_views(bool destroying)
|
|||||||
Saved_views::iterator q = this->saved_views_.begin();
|
Saved_views::iterator q = this->saved_views_.begin();
|
||||||
while (q != this->saved_views_.end())
|
while (q != this->saved_views_.end())
|
||||||
{
|
{
|
||||||
if (!(*q)->is_locked()
|
if (!(*q)->is_locked())
|
||||||
&& (destroying || !(*q)->should_cache()))
|
|
||||||
{
|
{
|
||||||
delete *q;
|
delete *q;
|
||||||
q = this->saved_views_.erase(q);
|
q = this->saved_views_.erase(q);
|
||||||
|
@ -46,8 +46,9 @@ class File_read
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
File_read()
|
File_read()
|
||||||
: name_(), descriptor_(-1), size_(0), token_(false), views_(),
|
: name_(), descriptor_(-1), object_count_(0), size_(0), token_(false),
|
||||||
saved_views_(), contents_(NULL), mapped_bytes_(0), released_(true)
|
views_(), saved_views_(), contents_(NULL), mapped_bytes_(0),
|
||||||
|
released_(true)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
~File_read();
|
~File_read();
|
||||||
@ -68,6 +69,16 @@ class File_read
|
|||||||
filename() const
|
filename() const
|
||||||
{ return this->name_; }
|
{ 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
|
// Lock the file for exclusive access within a particular Task::run
|
||||||
// execution. This means that the descriptor can not be closed.
|
// execution. This means that the descriptor can not be closed.
|
||||||
// This routine may only be called when the workqueue lock is held.
|
// This routine may only be called when the workqueue lock is held.
|
||||||
@ -126,6 +137,34 @@ class File_read
|
|||||||
File_view*
|
File_view*
|
||||||
get_lasting_view(off_t start, section_size_type size, bool cache);
|
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.
|
// Dump statistical information to stderr.
|
||||||
static void
|
static void
|
||||||
print_stats();
|
print_stats();
|
||||||
@ -154,7 +193,7 @@ class File_read
|
|||||||
View(off_t start, section_size_type size, const unsigned char* data,
|
View(off_t start, section_size_type size, const unsigned char* data,
|
||||||
bool cache, bool mapped)
|
bool cache, bool mapped)
|
||||||
: start_(start), size_(size), data_(data), lock_count_(0),
|
: start_(start), size_(size), data_(data), lock_count_(0),
|
||||||
cache_(cache), mapped_(mapped)
|
cache_(cache), mapped_(mapped), accessed_(true)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
~View();
|
~View();
|
||||||
@ -184,10 +223,26 @@ class File_read
|
|||||||
set_cache()
|
set_cache()
|
||||||
{ this->cache_ = true; }
|
{ this->cache_ = true; }
|
||||||
|
|
||||||
|
void
|
||||||
|
clear_cache()
|
||||||
|
{ this->cache_ = false; }
|
||||||
|
|
||||||
bool
|
bool
|
||||||
should_cache() const
|
should_cache() const
|
||||||
{ return this->cache_; }
|
{ return this->cache_; }
|
||||||
|
|
||||||
|
void
|
||||||
|
set_accessed()
|
||||||
|
{ this->accessed_ = true; }
|
||||||
|
|
||||||
|
void
|
||||||
|
clear_accessed()
|
||||||
|
{ this->accessed_= false; }
|
||||||
|
|
||||||
|
bool
|
||||||
|
accessed() const
|
||||||
|
{ return this->accessed_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
View(const View&);
|
View(const View&);
|
||||||
View& operator=(const View&);
|
View& operator=(const View&);
|
||||||
@ -198,6 +253,7 @@ class File_read
|
|||||||
int lock_count_;
|
int lock_count_;
|
||||||
bool cache_;
|
bool cache_;
|
||||||
bool mapped_;
|
bool mapped_;
|
||||||
|
bool accessed_;
|
||||||
};
|
};
|
||||||
|
|
||||||
friend class View;
|
friend class View;
|
||||||
@ -238,10 +294,20 @@ class File_read
|
|||||||
// A simple list of Views.
|
// A simple list of Views.
|
||||||
typedef std::list<View*> Saved_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.
|
// File name.
|
||||||
std::string name_;
|
std::string name_;
|
||||||
// File descriptor.
|
// File descriptor.
|
||||||
int 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.
|
// File size.
|
||||||
off_t size_;
|
off_t size_;
|
||||||
// A token used to lock the file.
|
// A token used to lock the 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);
|
off = this->set_section_offsets(off, BEFORE_INPUT_SECTIONS_PASS);
|
||||||
|
|
||||||
// Create the symbol table sections.
|
// 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())
|
if (!parameters->doing_static_link())
|
||||||
this->assign_local_dynsym_offsets(input_objects);
|
this->assign_local_dynsym_offsets(input_objects);
|
||||||
|
|
||||||
@ -1212,7 +1212,6 @@ Layout::count_local_symbols(const Task* task,
|
|||||||
void
|
void
|
||||||
Layout::create_symtab_sections(const Input_objects* input_objects,
|
Layout::create_symtab_sections(const Input_objects* input_objects,
|
||||||
Symbol_table* symtab,
|
Symbol_table* symtab,
|
||||||
const Task* task,
|
|
||||||
off_t* poff)
|
off_t* poff)
|
||||||
{
|
{
|
||||||
int symsize;
|
int symsize;
|
||||||
@ -1286,7 +1285,7 @@ Layout::create_symtab_sections(const Input_objects* input_objects,
|
|||||||
== this->dynsym_section_->data_size() - locsize);
|
== 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_);
|
dyncount, &this->sympool_);
|
||||||
|
|
||||||
if (!parameters->strip_all())
|
if (!parameters->strip_all())
|
||||||
|
@ -292,8 +292,7 @@ class Layout
|
|||||||
|
|
||||||
// Create the output sections for the symbol table.
|
// Create the output sections for the symbol table.
|
||||||
void
|
void
|
||||||
create_symtab_sections(const Input_objects*, Symbol_table*, const Task*,
|
create_symtab_sections(const Input_objects*, Symbol_table*, off_t*);
|
||||||
off_t*);
|
|
||||||
|
|
||||||
// Create the .shstrtab section.
|
// Create the .shstrtab section.
|
||||||
Output_section*
|
Output_section*
|
||||||
|
@ -125,7 +125,17 @@ Object::handle_gnu_warning_section(const char* name, unsigned int shndx,
|
|||||||
const int warn_prefix_len = sizeof warn_prefix - 1;
|
const int warn_prefix_len = sizeof warn_prefix - 1;
|
||||||
if (strncmp(name, warn_prefix, warn_prefix_len) == 0)
|
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 true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -404,7 +414,7 @@ Sized_relobj<size, big_endian>::include_section_group(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
off_t symoff = symshdr.get_sh_offset() + shdr.get_sh_info() * This::sym_size;
|
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);
|
elfcpp::Sym<size, big_endian> sym(psym);
|
||||||
|
|
||||||
// Read the symbol table names.
|
// Read the symbol table names.
|
||||||
@ -729,10 +739,11 @@ Sized_relobj<size, big_endian>::do_add_symbols(Symbol_table* symtab,
|
|||||||
sd->symbol_names = NULL;
|
sd->symbol_names = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finalize the local symbols. Here we add their names to *POOL and
|
// First pass over the local symbols. Here we add their names to
|
||||||
// *DYNPOOL, and we add their values to THIS->LOCAL_VALUES_. This
|
// *POOL and *DYNPOOL, and we store the symbol value in
|
||||||
// function is always called from a singleton thread. The actual
|
// THIS->LOCAL_VALUES_. This function is always called from a
|
||||||
// output of the local symbols will occur in a separate task.
|
// singleton thread. This is followed by a call to
|
||||||
|
// finalize_local_symbols.
|
||||||
|
|
||||||
template<int size, bool big_endian>
|
template<int size, bool big_endian>
|
||||||
void
|
void
|
||||||
@ -833,7 +844,7 @@ Sized_relobj<size, big_endian>::do_count_local_symbols(Stringpool* pool,
|
|||||||
this->output_local_dynsym_count_ = dyncount;
|
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->LOCAL_VALUES_ and set their output symbol table indexes.
|
||||||
// This function is always called from a singleton thread. The actual
|
// This function is always called from a singleton thread. The actual
|
||||||
// output of the local symbols will occur in a separate task.
|
// 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;
|
section_size_type strtab_size;
|
||||||
const unsigned char* pnamesu = this->section_contents(strtab_shndx,
|
const unsigned char* pnamesu = this->section_contents(strtab_shndx,
|
||||||
&strtab_size,
|
&strtab_size,
|
||||||
true);
|
false);
|
||||||
const char* pnames = reinterpret_cast<const char*>(pnamesu);
|
const char* pnames = reinterpret_cast<const char*>(pnamesu);
|
||||||
|
|
||||||
// Get views into the output file for the portions of the symbol table
|
// Get views into the output file for the portions of the symbol table
|
||||||
|
@ -139,10 +139,10 @@ class Object
|
|||||||
off_t offset = 0)
|
off_t offset = 0)
|
||||||
: name_(name), input_file_(input_file), offset_(offset), shnum_(-1U),
|
: name_(name), input_file_(input_file), offset_(offset), shnum_(-1U),
|
||||||
is_dynamic_(is_dynamic), target_(NULL)
|
is_dynamic_(is_dynamic), target_(NULL)
|
||||||
{ }
|
{ input_file->file().add_object(); }
|
||||||
|
|
||||||
virtual ~Object()
|
virtual ~Object()
|
||||||
{ }
|
{ this->input_file_->file().remove_object(); }
|
||||||
|
|
||||||
// Return the name of the object as we would report it to the tuser.
|
// Return the name of the object as we would report it to the tuser.
|
||||||
const std::string&
|
const std::string&
|
||||||
@ -294,6 +294,37 @@ class Object
|
|||||||
View view(Location loc)
|
View view(Location loc)
|
||||||
{ return View(this->get_view(loc.file_offset, loc.data_size, true)); }
|
{ 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:
|
protected:
|
||||||
// Read the symbols--implemented by child class.
|
// Read the symbols--implemented by child class.
|
||||||
virtual void
|
virtual void
|
||||||
@ -342,27 +373,6 @@ class Object
|
|||||||
input_file() const
|
input_file() const
|
||||||
{ return this->input_file_; }
|
{ 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.
|
// Set the target.
|
||||||
void
|
void
|
||||||
set_target(int machine, int size, bool big_endian, int osabi,
|
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
|
// Write section data to the output file. Record the views and
|
||||||
// sizes in VIEWS for use when relocating.
|
// sizes in VIEWS for use when relocating.
|
||||||
void
|
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.
|
// Relocate the sections in the output file.
|
||||||
void
|
void
|
||||||
@ -1229,6 +1239,15 @@ class Sized_relobj : public Relobj
|
|||||||
const Stringpool_template<char>*,
|
const Stringpool_template<char>*,
|
||||||
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
|
// The GOT offsets of local symbols. This map also stores GOT offsets
|
||||||
// for tp-relative offsets for TLS symbols.
|
// for tp-relative offsets for TLS symbols.
|
||||||
typedef Unordered_map<unsigned int, unsigned int> Local_got_offsets;
|
typedef Unordered_map<unsigned int, unsigned int> Local_got_offsets;
|
||||||
|
@ -22,6 +22,8 @@
|
|||||||
|
|
||||||
#include "gold.h"
|
#include "gold.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include "workqueue.h"
|
#include "workqueue.h"
|
||||||
#include "symtab.h"
|
#include "symtab.h"
|
||||||
#include "output.h"
|
#include "output.h"
|
||||||
@ -159,6 +161,11 @@ Relocate_task::run(Workqueue*)
|
|||||||
{
|
{
|
||||||
this->object_->relocate(this->options_, this->symtab_, this->layout_,
|
this->object_->relocate(this->options_, this->symtab_, this->layout_,
|
||||||
this->of_);
|
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();
|
this->object_->release();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -376,8 +383,20 @@ Sized_relobj<size, big_endian>::do_relocate(const General_options& options,
|
|||||||
|
|
||||||
// Write out the local symbols.
|
// Write out the local symbols.
|
||||||
this->write_local_symbols(of, layout->sympool(), layout->dynpool());
|
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
|
// Write section data to the output file. PSHDRS points to the
|
||||||
// section headers. Record the views in *PVIEWS for use when
|
// section headers. Record the views in *PVIEWS for use when
|
||||||
// relocating.
|
// relocating.
|
||||||
@ -386,11 +405,14 @@ template<int size, bool big_endian>
|
|||||||
void
|
void
|
||||||
Sized_relobj<size, big_endian>::write_sections(const unsigned char* pshdrs,
|
Sized_relobj<size, big_endian>::write_sections(const unsigned char* pshdrs,
|
||||||
Output_file* of,
|
Output_file* of,
|
||||||
Views* pviews) const
|
Views* pviews)
|
||||||
{
|
{
|
||||||
unsigned int shnum = this->shnum();
|
unsigned int shnum = this->shnum();
|
||||||
const std::vector<Map_to_output>& map_sections(this->map_to_output());
|
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;
|
const unsigned char* p = pshdrs + This::shdr_size;
|
||||||
for (unsigned int i = 1; i < shnum; ++i, p += 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();
|
unsigned char* buffer = os->postprocessing_buffer();
|
||||||
view = buffer + view_start;
|
view = buffer + view_start;
|
||||||
if (output_offset != -1)
|
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
|
else
|
||||||
{
|
{
|
||||||
@ -477,7 +505,11 @@ Sized_relobj<size, big_endian>::write_sections(const unsigned char* pshdrs,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
view = of->get_output_view(view_start, view_size);
|
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_input_output_view = output_offset == -1;
|
||||||
pvs->is_postprocessing_view = os->requires_postprocessing();
|
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
|
// Relocate section data. VIEWS points to the section data as views
|
||||||
|
@ -1403,8 +1403,8 @@ Symbol_table::set_dynsym_indexes(const Target* target,
|
|||||||
// OFF. Add their names to POOL. Return the new file offset.
|
// OFF. Add their names to POOL. Return the new file offset.
|
||||||
|
|
||||||
off_t
|
off_t
|
||||||
Symbol_table::finalize(const Task* task, unsigned int index, off_t off,
|
Symbol_table::finalize(unsigned int index, off_t off, off_t dynoff,
|
||||||
off_t dynoff, size_t dyn_global_index, size_t dyncount,
|
size_t dyn_global_index, size_t dyncount,
|
||||||
Stringpool* pool)
|
Stringpool* pool)
|
||||||
{
|
{
|
||||||
off_t ret;
|
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
|
// Now that we have the final symbol table, we can reliably note
|
||||||
// which symbols should get warnings.
|
// which symbols should get warnings.
|
||||||
this->warnings_.note_warnings(this, task);
|
this->warnings_.note_warnings(this);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -2004,10 +2004,10 @@ Symbol_table::detect_odr_violations(const Task* task,
|
|||||||
|
|
||||||
void
|
void
|
||||||
Warnings::add_warning(Symbol_table* symtab, const char* name, Object* obj,
|
Warnings::add_warning(Symbol_table* symtab, const char* name, Object* obj,
|
||||||
unsigned int shndx)
|
const std::string& warning)
|
||||||
{
|
{
|
||||||
name = symtab->canonicalize_name(name);
|
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
|
// 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.
|
// sources for all the symbols.
|
||||||
|
|
||||||
void
|
void
|
||||||
Warnings::note_warnings(Symbol_table* symtab, const Task* task)
|
Warnings::note_warnings(Symbol_table* symtab)
|
||||||
{
|
{
|
||||||
for (Warning_table::iterator p = this->warnings_.begin();
|
for (Warning_table::iterator p = this->warnings_.begin();
|
||||||
p != this->warnings_.end();
|
p != this->warnings_.end();
|
||||||
@ -2025,24 +2025,7 @@ Warnings::note_warnings(Symbol_table* symtab, const Task* task)
|
|||||||
if (sym != NULL
|
if (sym != NULL
|
||||||
&& sym->source() == Symbol::FROM_OBJECT
|
&& sym->source() == Symbol::FROM_OBJECT
|
||||||
&& sym->object() == p->second.object)
|
&& sym->object() == p->second.object)
|
||||||
{
|
|
||||||
sym->set_has_warning();
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -897,15 +897,16 @@ class Warnings
|
|||||||
: 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
|
void
|
||||||
add_warning(Symbol_table* symtab, const char* name, Object* obj,
|
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
|
// For each symbol for which we should give a warning, make a note
|
||||||
// on the symbol.
|
// on the symbol.
|
||||||
void
|
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.
|
// Issue a warning for a reference to SYM at RELINFO's location.
|
||||||
template<int size, bool big_endian>
|
template<int size, bool big_endian>
|
||||||
@ -922,25 +923,19 @@ class Warnings
|
|||||||
{
|
{
|
||||||
// The object the warning is in.
|
// The object the warning is in.
|
||||||
Object* object;
|
Object* object;
|
||||||
// The index of the warning section.
|
// The warning text.
|
||||||
unsigned int shndx;
|
|
||||||
// The warning text if we have already loaded it.
|
|
||||||
std::string text;
|
std::string text;
|
||||||
|
|
||||||
Warning_location()
|
Warning_location()
|
||||||
: object(NULL), shndx(0), text()
|
: object(NULL), text()
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
void
|
void
|
||||||
set(Object* o, unsigned int s)
|
set(Object* o, const std::string& t)
|
||||||
{
|
{
|
||||||
this->object = o;
|
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
|
// A mapping from warning symbol names (canonicalized in
|
||||||
@ -1057,10 +1052,11 @@ class Symbol_table
|
|||||||
void
|
void
|
||||||
allocate_commons(const General_options&, Layout*);
|
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
|
void
|
||||||
add_warning(const char* name, Object* obj, unsigned int shndx)
|
add_warning(const char* name, Object* obj, const std::string& warning)
|
||||||
{ this->warnings_.add_warning(this, name, obj, shndx); }
|
{ this->warnings_.add_warning(this, name, obj, warning); }
|
||||||
|
|
||||||
// Canonicalize a symbol name for use in the hash table.
|
// Canonicalize a symbol name for use in the hash table.
|
||||||
const char*
|
const char*
|
||||||
@ -1103,7 +1099,7 @@ class Symbol_table
|
|||||||
// symbol, and DYNCOUNT is the number of global dynamic symbols.
|
// symbol, and DYNCOUNT is the number of global dynamic symbols.
|
||||||
// This records the parameters, and returns the new file offset.
|
// This records the parameters, and returns the new file offset.
|
||||||
off_t
|
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);
|
size_t dyn_global_index, size_t dyncount, Stringpool* pool);
|
||||||
|
|
||||||
// Write out the global symbols.
|
// Write out the global symbols.
|
||||||
|
Reference in New Issue
Block a user