Implement --whole-archive.

This commit is contained in:
Ian Lance Taylor 2007-08-21 23:37:56 +00:00
parent 72a2eed757
commit 4973341a7d
5 changed files with 146 additions and 28 deletions

View file

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

View file

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

View file

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

View 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)
{
}

View file

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