Implement --whole-archive.
This commit is contained in:
parent
72a2eed757
commit
4973341a7d
5 changed files with 146 additions and 28 deletions
112
gold/archive.cc
112
gold/archive.cc
|
@ -57,16 +57,45 @@ Archive::setup()
|
|||
// The first member of the archive should be the symbol table.
|
||||
std::string armap_name;
|
||||
off_t armap_size = this->read_header(sarmag, &armap_name);
|
||||
if (!armap_name.empty())
|
||||
off_t off;
|
||||
if (armap_name.empty())
|
||||
{
|
||||
this->read_armap(sarmag + sizeof(Archive_header), armap_size);
|
||||
off = sarmag + sizeof(Archive_header) + armap_size;
|
||||
}
|
||||
else if (!this->input_file_->options().include_whole_archive())
|
||||
{
|
||||
fprintf(stderr, _("%s: %s: no archive symbol table (run ranlib)\n"),
|
||||
program_name, this->name().c_str());
|
||||
gold_exit(false);
|
||||
}
|
||||
else
|
||||
off = sarmag;
|
||||
|
||||
// See if there is an extended name table.
|
||||
if ((off & 1) != 0)
|
||||
++off;
|
||||
std::string xname;
|
||||
off_t extended_size = this->read_header(off, &xname);
|
||||
if (xname == "/")
|
||||
{
|
||||
const unsigned char* p = this->get_view(off + sizeof(Archive_header),
|
||||
extended_size);
|
||||
const char* px = reinterpret_cast<const char*>(p);
|
||||
this->extended_names_.assign(px, extended_size);
|
||||
}
|
||||
|
||||
// Opening the file locked it. Unlock it now.
|
||||
this->input_file_->file().unlock();
|
||||
}
|
||||
|
||||
// Read the archive symbol map.
|
||||
|
||||
void
|
||||
Archive::read_armap(off_t start, off_t size)
|
||||
{
|
||||
// Read in the entire armap.
|
||||
const unsigned char* p = this->get_view(sarmag + sizeof(Archive_header),
|
||||
armap_size);
|
||||
const unsigned char* p = this->get_view(start, size);
|
||||
|
||||
// Numbers in the armap are always big-endian.
|
||||
const elfcpp::Elf_Word* pword = reinterpret_cast<const elfcpp::Elf_Word*>(p);
|
||||
|
@ -86,32 +115,16 @@ Archive::setup()
|
|||
++pword;
|
||||
}
|
||||
|
||||
if (reinterpret_cast<const unsigned char*>(pnames) - p > armap_size)
|
||||
if (reinterpret_cast<const unsigned char*>(pnames) - p > size)
|
||||
{
|
||||
fprintf(stderr, _("%s: %s: bad archive symbol table names\n"),
|
||||
program_name, this->name().c_str());
|
||||
gold_exit(false);
|
||||
}
|
||||
|
||||
// See if there is an extended name table.
|
||||
off_t off = sarmag + sizeof(Archive_header) + armap_size;
|
||||
if ((off & 1) != 0)
|
||||
++off;
|
||||
std::string xname;
|
||||
off_t extended_size = this->read_header(off, &xname);
|
||||
if (xname == "/")
|
||||
{
|
||||
p = this->get_view(off + sizeof(Archive_header), extended_size);
|
||||
const char* px = reinterpret_cast<const char*>(p);
|
||||
this->extended_names_.assign(px, extended_size);
|
||||
}
|
||||
|
||||
// This array keeps track of which symbols are for archive elements
|
||||
// which we have already included in the link.
|
||||
this->seen_.resize(nsyms);
|
||||
|
||||
// Opening the file locked it. Unlock it now.
|
||||
this->input_file_->file().unlock();
|
||||
}
|
||||
|
||||
// Read the header of an archive member at OFF. Fail if something
|
||||
|
@ -123,7 +136,17 @@ Archive::read_header(off_t off, std::string* pname)
|
|||
{
|
||||
const unsigned char* p = this->get_view(off, sizeof(Archive_header));
|
||||
const Archive_header* hdr = reinterpret_cast<const Archive_header*>(p);
|
||||
return this->interpret_header(hdr, off, pname);
|
||||
}
|
||||
|
||||
// Interpret the header of HDR, the header of the archive member at
|
||||
// file offset OFF. Fail if something goes wrong. Return the size of
|
||||
// the member. Set *PNAME to the name of the member.
|
||||
|
||||
off_t
|
||||
Archive::interpret_header(const Archive_header* hdr, off_t off,
|
||||
std::string* pname)
|
||||
{
|
||||
if (memcmp(hdr->ar_fmag, arfmag, sizeof arfmag) != 0)
|
||||
{
|
||||
fprintf(stderr, _("%s; %s: malformed archive header at %ld\n"),
|
||||
|
@ -218,6 +241,9 @@ void
|
|||
Archive::add_symbols(const General_options& options, Symbol_table* symtab,
|
||||
Layout* layout, Input_objects* input_objects)
|
||||
{
|
||||
if (this->input_file_->options().include_whole_archive())
|
||||
return this->include_all_members(options, symtab, layout, input_objects);
|
||||
|
||||
const size_t armap_size = this->armap_.size();
|
||||
|
||||
bool added_new_object;
|
||||
|
@ -256,6 +282,52 @@ Archive::add_symbols(const General_options& options, Symbol_table* symtab,
|
|||
while (added_new_object);
|
||||
}
|
||||
|
||||
// Include all the archive members in the link. This is for --whole-archive.
|
||||
|
||||
void
|
||||
Archive::include_all_members(const General_options& options,
|
||||
Symbol_table* symtab, Layout* layout,
|
||||
Input_objects* input_objects)
|
||||
{
|
||||
off_t off = sarmag;
|
||||
while (true)
|
||||
{
|
||||
off_t bytes;
|
||||
const unsigned char* p = this->get_view(off, sizeof(Archive_header),
|
||||
&bytes);
|
||||
if (bytes < sizeof(Archive_header))
|
||||
{
|
||||
if (bytes != 0)
|
||||
{
|
||||
fprintf(stderr, _("%s: %s: short archive header at %ld\n"),
|
||||
program_name, this->name().c_str(),
|
||||
static_cast<long>(off));
|
||||
gold_exit(false);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
const Archive_header* hdr = reinterpret_cast<const Archive_header*>(p);
|
||||
std::string name;
|
||||
off_t size = this->interpret_header(hdr, off, &name);
|
||||
if (name.empty())
|
||||
{
|
||||
// Symbol table.
|
||||
}
|
||||
else if (name == "/")
|
||||
{
|
||||
// Extended name table.
|
||||
}
|
||||
else
|
||||
this->include_member(options, symtab, layout, input_objects, off);
|
||||
|
||||
off += sizeof(Archive_header) + size;
|
||||
if ((off & 1) != 0)
|
||||
++off;
|
||||
}
|
||||
}
|
||||
|
||||
// Include an archive member in the link. OFF is the file offset of
|
||||
// the member header.
|
||||
|
||||
|
|
|
@ -79,14 +79,28 @@ class Archive
|
|||
|
||||
// Get a view into the underlying file.
|
||||
const unsigned char*
|
||||
get_view(off_t start, off_t size)
|
||||
{ return this->input_file_->file().get_view(start, size); }
|
||||
get_view(off_t start, off_t size, off_t* pbytes = NULL)
|
||||
{ return this->input_file_->file().get_view(start, size, pbytes); }
|
||||
|
||||
// Read the archive symbol map.
|
||||
void
|
||||
read_armap(off_t start, off_t size);
|
||||
|
||||
// Read an archive member header at OFF. Return the size of the
|
||||
// member, and set *PNAME to the name.
|
||||
off_t
|
||||
read_header(off_t off, std::string* pname);
|
||||
|
||||
// Interpret an archive header HDR at OFF. Return the size of the
|
||||
// member, and set *PNAME to the name.
|
||||
off_t
|
||||
interpret_header(const Archive_header* hdr, off_t off, std::string* pname);
|
||||
|
||||
// Include all the archive members in the link.
|
||||
void
|
||||
include_all_members(const General_options&, Symbol_table*, Layout*,
|
||||
Input_objects*);
|
||||
|
||||
// Include an archive member in the link.
|
||||
void
|
||||
include_member(const General_options&, Symbol_table*, Layout*,
|
||||
|
|
|
@ -240,6 +240,12 @@ class Input_file
|
|||
filename() const
|
||||
{ return this->file_.filename(); }
|
||||
|
||||
// Return the position dependent options.
|
||||
const Position_dependent_options&
|
||||
options() const
|
||||
{ return this->input_argument_->options(); }
|
||||
|
||||
// Return the file.
|
||||
File_read&
|
||||
file()
|
||||
{ return this->file_; }
|
||||
|
|
|
@ -257,6 +257,14 @@ options::Command_line_options::options[] =
|
|||
POSDEP_NOARG('\0', "no-as-needed",
|
||||
N_("Always DT_NEEDED for following dynamic libs (default)"),
|
||||
NULL, TWO_DASHES, &Position_dependent_options::clear_as_needed),
|
||||
POSDEP_NOARG('\0', "whole-archive",
|
||||
N_("Include all archive contents"),
|
||||
NULL, TWO_DASHES,
|
||||
&Position_dependent_options::set_whole_archive),
|
||||
POSDEP_NOARG('\0', "no-whole-archive",
|
||||
N_("Include only needed archive contents"),
|
||||
NULL, TWO_DASHES,
|
||||
&Position_dependent_options::clear_whole_archive),
|
||||
SPECIAL('\0', "help", N_("Report usage information"), NULL,
|
||||
TWO_DASHES, &help)
|
||||
};
|
||||
|
@ -271,6 +279,7 @@ General_options::General_options()
|
|||
search_path_(),
|
||||
output_file_name_("a.out"),
|
||||
is_relocatable_(false),
|
||||
rpath_(),
|
||||
is_shared_(false),
|
||||
is_static_(false)
|
||||
{
|
||||
|
@ -279,7 +288,9 @@ General_options::General_options()
|
|||
// The default values for the position dependent options.
|
||||
|
||||
Position_dependent_options::Position_dependent_options()
|
||||
: do_static_search_(false)
|
||||
: do_static_search_(false),
|
||||
as_needed_(false),
|
||||
include_whole_archive_(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -142,6 +142,12 @@ class Position_dependent_options
|
|||
as_needed() const
|
||||
{ return this->as_needed_; }
|
||||
|
||||
// --whole-archive: Whether to include the entire contents of an
|
||||
// --archive.
|
||||
bool
|
||||
include_whole_archive() const
|
||||
{ return this->include_whole_archive_; }
|
||||
|
||||
void
|
||||
set_static_search()
|
||||
{ this->do_static_search_ = true; }
|
||||
|
@ -158,9 +164,18 @@ class Position_dependent_options
|
|||
clear_as_needed()
|
||||
{ this->as_needed_ = false; }
|
||||
|
||||
void
|
||||
set_whole_archive()
|
||||
{ this->include_whole_archive_ = true; }
|
||||
|
||||
void
|
||||
clear_whole_archive()
|
||||
{ this->include_whole_archive_ = false; }
|
||||
|
||||
private:
|
||||
bool do_static_search_;
|
||||
bool as_needed_;
|
||||
bool include_whole_archive_;
|
||||
};
|
||||
|
||||
// A single file or library argument from the command line.
|
||||
|
|
Loading…
Reference in a new issue