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.
|
// The first member of the archive should be the symbol table.
|
||||||
std::string armap_name;
|
std::string armap_name;
|
||||||
off_t armap_size = this->read_header(sarmag, &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"),
|
fprintf(stderr, _("%s: %s: no archive symbol table (run ranlib)\n"),
|
||||||
program_name, this->name().c_str());
|
program_name, this->name().c_str());
|
||||||
gold_exit(false);
|
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.
|
// Read in the entire armap.
|
||||||
const unsigned char* p = this->get_view(sarmag + sizeof(Archive_header),
|
const unsigned char* p = this->get_view(start, size);
|
||||||
armap_size);
|
|
||||||
|
|
||||||
// Numbers in the armap are always big-endian.
|
// Numbers in the armap are always big-endian.
|
||||||
const elfcpp::Elf_Word* pword = reinterpret_cast<const elfcpp::Elf_Word*>(p);
|
const elfcpp::Elf_Word* pword = reinterpret_cast<const elfcpp::Elf_Word*>(p);
|
||||||
|
@ -86,32 +115,16 @@ Archive::setup()
|
||||||
++pword;
|
++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"),
|
fprintf(stderr, _("%s: %s: bad archive symbol table names\n"),
|
||||||
program_name, this->name().c_str());
|
program_name, this->name().c_str());
|
||||||
gold_exit(false);
|
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
|
// This array keeps track of which symbols are for archive elements
|
||||||
// which we have already included in the link.
|
// which we have already included in the link.
|
||||||
this->seen_.resize(nsyms);
|
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
|
// 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 unsigned char* p = this->get_view(off, sizeof(Archive_header));
|
||||||
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
if (memcmp(hdr->ar_fmag, arfmag, sizeof arfmag) != 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, _("%s; %s: malformed archive header at %ld\n"),
|
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,
|
Archive::add_symbols(const General_options& options, Symbol_table* symtab,
|
||||||
Layout* layout, Input_objects* input_objects)
|
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();
|
const size_t armap_size = this->armap_.size();
|
||||||
|
|
||||||
bool added_new_object;
|
bool added_new_object;
|
||||||
|
@ -256,6 +282,52 @@ Archive::add_symbols(const General_options& options, Symbol_table* symtab,
|
||||||
while (added_new_object);
|
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
|
// Include an archive member in the link. OFF is the file offset of
|
||||||
// the member header.
|
// the member header.
|
||||||
|
|
||||||
|
|
|
@ -79,14 +79,28 @@ class Archive
|
||||||
|
|
||||||
// Get a view into the underlying file.
|
// Get a view into the underlying file.
|
||||||
const unsigned char*
|
const unsigned char*
|
||||||
get_view(off_t start, off_t size)
|
get_view(off_t start, off_t size, off_t* pbytes = NULL)
|
||||||
{ return this->input_file_->file().get_view(start, size); }
|
{ 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
|
// Read an archive member header at OFF. Return the size of the
|
||||||
// member, and set *PNAME to the name.
|
// member, and set *PNAME to the name.
|
||||||
off_t
|
off_t
|
||||||
read_header(off_t off, std::string* pname);
|
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.
|
// Include an archive member in the link.
|
||||||
void
|
void
|
||||||
include_member(const General_options&, Symbol_table*, Layout*,
|
include_member(const General_options&, Symbol_table*, Layout*,
|
||||||
|
|
|
@ -240,6 +240,12 @@ class Input_file
|
||||||
filename() const
|
filename() const
|
||||||
{ return this->file_.filename(); }
|
{ 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_read&
|
||||||
file()
|
file()
|
||||||
{ return this->file_; }
|
{ return this->file_; }
|
||||||
|
|
|
@ -257,6 +257,14 @@ options::Command_line_options::options[] =
|
||||||
POSDEP_NOARG('\0', "no-as-needed",
|
POSDEP_NOARG('\0', "no-as-needed",
|
||||||
N_("Always DT_NEEDED for following dynamic libs (default)"),
|
N_("Always DT_NEEDED for following dynamic libs (default)"),
|
||||||
NULL, TWO_DASHES, &Position_dependent_options::clear_as_needed),
|
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,
|
SPECIAL('\0', "help", N_("Report usage information"), NULL,
|
||||||
TWO_DASHES, &help)
|
TWO_DASHES, &help)
|
||||||
};
|
};
|
||||||
|
@ -271,6 +279,7 @@ General_options::General_options()
|
||||||
search_path_(),
|
search_path_(),
|
||||||
output_file_name_("a.out"),
|
output_file_name_("a.out"),
|
||||||
is_relocatable_(false),
|
is_relocatable_(false),
|
||||||
|
rpath_(),
|
||||||
is_shared_(false),
|
is_shared_(false),
|
||||||
is_static_(false)
|
is_static_(false)
|
||||||
{
|
{
|
||||||
|
@ -279,7 +288,9 @@ General_options::General_options()
|
||||||
// The default values for the position dependent options.
|
// The default values for the position dependent options.
|
||||||
|
|
||||||
Position_dependent_options::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
|
as_needed() const
|
||||||
{ return this->as_needed_; }
|
{ 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
|
void
|
||||||
set_static_search()
|
set_static_search()
|
||||||
{ this->do_static_search_ = true; }
|
{ this->do_static_search_ = true; }
|
||||||
|
@ -158,9 +164,18 @@ class Position_dependent_options
|
||||||
clear_as_needed()
|
clear_as_needed()
|
||||||
{ this->as_needed_ = false; }
|
{ this->as_needed_ = false; }
|
||||||
|
|
||||||
|
void
|
||||||
|
set_whole_archive()
|
||||||
|
{ this->include_whole_archive_ = true; }
|
||||||
|
|
||||||
|
void
|
||||||
|
clear_whole_archive()
|
||||||
|
{ this->include_whole_archive_ = false; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool do_static_search_;
|
bool do_static_search_;
|
||||||
bool as_needed_;
|
bool as_needed_;
|
||||||
|
bool include_whole_archive_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// A single file or library argument from the command line.
|
// A single file or library argument from the command line.
|
||||||
|
|
Loading…
Reference in a new issue