aboutsummaryrefslogtreecommitdiff
path: root/gold
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@google.com>2007-08-21 23:37:56 +0000
committerIan Lance Taylor <iant@google.com>2007-08-21 23:37:56 +0000
commit4973341a7d985b4d211b0b2ce14d95e2c05dbd37 (patch)
treef9e70df85ba58125e976bc2377bcdcf3d463bd51 /gold
parent72a2eed757d46b207f6e127dcc7c5acf848f5872 (diff)
downloadfsf-binutils-gdb-4973341a7d985b4d211b0b2ce14d95e2c05dbd37.zip
fsf-binutils-gdb-4973341a7d985b4d211b0b2ce14d95e2c05dbd37.tar.gz
fsf-binutils-gdb-4973341a7d985b4d211b0b2ce14d95e2c05dbd37.tar.bz2
Implement --whole-archive.
Diffstat (limited to 'gold')
-rw-r--r--gold/archive.cc116
-rw-r--r--gold/archive.h18
-rw-r--r--gold/fileread.h12
-rw-r--r--gold/options.cc13
-rw-r--r--gold/options.h15
5 files changed, 146 insertions, 28 deletions
diff --git a/gold/archive.cc b/gold/archive.cc
index d085403..51a0f48 100644
--- a/gold/archive.cc
+++ b/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.
@@ -339,7 +411,7 @@ class Add_archive_symbols::Add_archive_symbols_locker : public Task_locker
private:
Task_locker_block blocker_;
- Task_locker_obj<File_read> filelock_;
+ Task_locker_obj<File_read> filelock_;
};
Task_locker*
@@ -354,7 +426,7 @@ void
Add_archive_symbols::run(Workqueue*)
{
this->archive_->add_symbols(this->options_, this->symtab_, this->layout_,
- this->input_objects_);
+ this->input_objects_);
if (this->input_group_ != NULL)
this->input_group_->add_archive(this->archive_);
diff --git a/gold/archive.h b/gold/archive.h
index 193a9e2..ddd665f 100644
--- a/gold/archive.h
+++ b/gold/archive.h
@@ -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*,
diff --git a/gold/fileread.h b/gold/fileread.h
index 178e7f3..f3ac753 100644
--- a/gold/fileread.h
+++ b/gold/fileread.h
@@ -55,7 +55,7 @@ class File_read
// Unlock the descriptor, permitting it to be closed if necessary.
void
unlock();
-
+
// Test whether the object is locked.
bool
is_locked();
@@ -65,12 +65,12 @@ class File_read
// we can not read enough data. Otherwise *PBYTES is set to the
// number of bytes read.
const unsigned char*
- get_view(off_t start, off_t size, off_t *pbytes = NULL);
+ get_view(off_t start, off_t size, off_t* pbytes = NULL);
// Read data from the file into the buffer P. PBYTES is as in
// get_view.
void
- read(off_t start, off_t size, void* p, off_t *pbytes = NULL);
+ read(off_t start, off_t size, void* p, off_t* pbytes = NULL);
// Return a lasting view into the file. This is allocated with new,
// and the caller is responsible for deleting it when done. The
@@ -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_; }
diff --git a/gold/options.cc b/gold/options.cc
index 36e0044..0b858a2 100644
--- a/gold/options.cc
+++ b/gold/options.cc
@@ -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)
{
}
diff --git a/gold/options.h b/gold/options.h
index dc38b2f..3c13deb 100644
--- a/gold/options.h
+++ b/gold/options.h
@@ -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.