This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[gold][patch] Record the number of members in an archive


This is mostly an work in progress patch and I can split it a bit if
desired. In particular, the fixes for the typos and
Incremental_inputs_write can go in an independent patch.

What this patch does:

*) Fix typos in incremental-dump.cc and extend it a bit. A
Incremental_inputs_read is probably needed as it is getting
complicated.
*) Define readers and writers for archive information
*) Define an Archive_info structure. This is what
Incremental_inputs::report_archive records. For now it is just the
member count.
*) Define a Incremental_inputs_write class. This is a helper for
sized_create_inputs_section_data. Its main job is to compute and store
the layout of the incremental_inputs section.
*) Allocate space for archive and archive members
*) Write the member count
*) Write 0 as the offset of script files.

Particular items I would like feedback on:

*) In what order should the archive info be placed in the output? My
understanding is that it is not important since we always get to it
via a input file entry.

*) Incremental_inputs_write is implemented to be used with two passes
over the inputs. With this design it is possible to avoid additional
memory allocation.

Some alternatives:

*) Change it to resize the buffer as needed. This would allow us to do
a single pass over the inputs, but I am not sure if it would actually
be faster.

*) Spilt a Incremental_inputs_layout class out of it. This class would
not keep the buffer, just the counters necessary to find the size of
each part of the section. This classs could be updated from
incremental_inputs::report_*. I think that with this change
sized_create_inputs_section_data can be written to do a single pass
over the inputs and not use additional memory.

2009-11-30  Rafael Avila de Espindola  <espindola@google.com>

	* incremental-dump.cc (main): Fix typos. Print archive member count.
	* incremental.cc (Incremental_inputs_archive_header,
	Incremental_inputs_archive_header_write,
	Incremental_inputs_archive_member,
	Incremental_inputs_archive_member_write): New.
	(Incremental_inputs::report_archive): Record the member count.
	(Incremental_inputs_write): New.
	(Incremental_inputs::sized_create_inputs_section_data): Use
	Incremental_inputs_write. Write the archive member count.
	* incremental.h (Incremental_inputs_archive_header_data,
	Incremental_inputs_archive_member_data, Archive_info): New.
	(Input_info): Use Archive_info.

Cheers,
-- 
Rafael Ãvila de EspÃndola
diff --git a/gold/incremental-dump.cc b/gold/incremental-dump.cc
index 0d29263..2d5e743 100644
--- a/gold/incremental-dump.cc
+++ b/gold/incremental-dump.cc
@@ -94,7 +94,7 @@ main(int argc, char** argv)
 
   if (incremental_header->version != 1)
     {
-      fprintf(stderr, "%s: %s: unknown incremestal version %d\n", argv[0],
+      fprintf(stderr, "%s: %s: unknown incremental version %d\n", argv[0],
               filename, incremental_header->version);
       return 1;
     }
@@ -156,16 +156,28 @@ main(int argc, char** argv)
       switch (input->input_type)
       {
       case INCREMENTAL_INPUT_OBJECT:
-        printf("Abject\n");
+        printf("Object\n");
         break;
       case INCREMENTAL_INPUT_ARCHIVE:
-        printf("Archive\n");
+        {
+          printf("Archive\n");
+          const Incremental_inputs_archive_header_data* archive_header =
+            reinterpret_cast<const Incremental_inputs_archive_header_data*>
+            (((const unsigned char *)incremental_header) + input->data_offset);
+          printf("    Members count: %d\n", archive_header->member_count);
+        }
         break;
       case INCREMENTAL_INPUT_SHARED_LIBRARY:
         printf("Shared library\n");
         break;
       case INCREMENTAL_INPUT_SCRIPT:
         printf("Linker script\n");
+        if (input->data_offset != 0)
+          {
+            fprintf(stderr,"%s: %s: %u is a script but offset is not zero",
+                    argv[0], filename, i);
+            return 1;
+          }
         break;
       case INCREMENTAL_INPUT_INVALID:
       default:
diff --git a/gold/incremental.cc b/gold/incremental.cc
index 97b3eea..8dd12e5 100644
--- a/gold/incremental.cc
+++ b/gold/incremental.cc
@@ -199,6 +199,106 @@ class Incremental_inputs_entry_write
   Data_type* p_;
 };
 
+// Reader class for an .gnu_incremental_inputs archive header. See
+// Incremental_inputs_archive_header_data for fields descriptions.
+template<int size, bool big_endian>
+class Incremental_inputs_archive_header
+{
+ private:
+  typedef Incremental_inputs_archive_header_data data_type;
+
+ public:
+  Incremental_inputs_archive_header(const unsigned char *p)
+    : p_(reinterpret_cast<const data_type*>(p))
+  { }
+
+  static const int data_size = sizeof(data_type);
+
+  elfcpp::Elf_Word
+  get_member_count(elfcpp::Elf_Word v)
+  { return Convert<32, big_endian>::convert_host(this->p_->member_count); }
+
+ private:
+  const data_type* p_;
+};
+
+// Writer class for an .gnu_incremental_inputs archive header. See
+// Incremental_inputs_archive_header_data for fields descriptions.
+template<int size, bool big_endian>
+class Incremental_inputs_archive_header_write
+{
+ private:
+  typedef Incremental_inputs_archive_header_data data_type;
+
+ public:
+  Incremental_inputs_archive_header_write(unsigned char *p)
+    : p_(reinterpret_cast<data_type*>(p))
+  { }
+
+  static const int data_size = sizeof(data_type);
+
+  void
+  put_member_count(elfcpp::Elf_Word v)
+  { this->p_->member_count = Convert<32, big_endian>::convert_host(v); }
+
+ private:
+  data_type* p_;
+};
+
+// Reader class for an .gnu_incremental_inputs archive member. See
+// Incremental_inputs_archive_member_data for fields descriptions.
+template<int size, bool big_endian>
+class Incremental_inputs_archive_member
+{
+ private:
+  typedef Incremental_inputs_archive_member_data data_type;
+
+ public:
+  Incremental_inputs_archive_member(const unsigned char *p)
+    : p_(reinterpret_cast<const data_type*>(p))
+  { }
+
+  static const int data_size = sizeof(data_type);
+
+  elfcpp::Elf_Word
+  get_data_offset(elfcpp::Elf_Word v)
+  { return Convert<32, big_endian>::convert_host(this->p_->data_offset); }
+
+  elfcpp::Elf_Word
+  get_reserved(elfcpp::Elf_Word v)
+  { return Convert<32, big_endian>::convert_host(this->p_->reserved); }
+
+ private:
+  const data_type* p_;
+};
+
+// Writer class for an .gnu_incremental_inputs archive member. See
+// Incremental_inputs_archive_member_data for fields descriptions.
+template<int size, bool big_endian>
+class Incremental_inputs_archive_member_write
+{
+ private:
+  typedef Incremental_inputs_archive_member_data data_type;
+
+ public:
+  Incremental_inputs_archive_member_write(const unsigned char *p)
+    : p_(reinterpret_cast<const data_type*>(p))
+  { }
+
+  static const int data_size = sizeof(data_type);
+
+  void
+  put_data_offset(elfcpp::Elf_Word v)
+  { this->p_->data_offset = Convert<32, big_endian>::convert_host(v); }
+
+  void
+  put_reserved(elfcpp::Elf_Word v)
+  { this->p_->reserved = Convert<32, big_endian>::convert_host(v); }
+
+ public:
+  data_type* p_;
+};
+
 // Inform the user why we don't do an incremental link.  Not called in
 // the obvious case of missing output file.  TODO: Is this helpful?
 
@@ -480,9 +580,12 @@ Incremental_inputs::report_archive(const Input_argument* input,
 {
   Hold_lock hl(*this->lock_);
 
+  Archive_info archive_info;
+  archive_info.member_count = archive->count_members();
+
   Input_info info;
   info.type = INCREMENTAL_INPUT_ARCHIVE;
-  info.archive = archive;
+  info.archive = archive_info;
   info.mtime = archive->file().get_mtime();
   this->inputs_map_.insert(std::make_pair(input, info));
 }
@@ -614,22 +717,152 @@ Incremental_inputs::create_incremental_inputs_section_data()
     }
 }
 
+template<int size, bool big_endian>
+class Incremental_inputs_write
+{
+ public:
+  Incremental_inputs_write() : archive_count_(0), archive_member_count_(0),
+                               object_count_(0), script_count_(0),
+                               current_archive_offset_(0), buffer_(NULL)
+  { }
+
+  void
+  add_script()
+  {
+    this->script_count_++;
+  }
+
+  void
+  add_object()
+  {
+    this->object_count_++;
+  }
+
+  void
+  add_archive(size_t member_count)
+  {
+    this->archive_member_count_ += member_count;
+    this->archive_count_++;
+  }
+
+  size_t
+  get_size()
+  {
+    size_t archive_size = this->archive_count_ * this->archive_header_size_ +
+        this->archive_member_count_ * this->archive_member_size_;
+    // FIXME: compute object_size;
+    size_t object_size = 0;
+    return this->header_size_ + get_common_size() + archive_size +object_size;
+  }
+
+  unsigned char*
+  get_buffer()
+  {
+    return this->buffer_;
+  }
+
+  size_t
+  get_current_archive_offset(size_t member_count)
+  {
+    size_t archive_size = this->archive_header_size_ +
+      member_count * this->archive_member_size_;
+    size_t ret = this->header_size_ + get_common_size() +
+      this->current_archive_offset_;
+    this->current_archive_offset_ += archive_size;
+    return ret;
+  }
+
+  void
+  allocate()
+  {
+    this->buffer_ = new unsigned char[this->get_size()];
+  }
+
+  Incremental_inputs_header_write<size, big_endian>
+  get_header_writer()
+  {
+    return Incremental_inputs_header_write<size, big_endian>(this->buffer_);
+  }
+
+  Incremental_inputs_entry_write<size, big_endian>
+  get_entry_writer(size_t index)
+  {
+    return Incremental_inputs_entry_write<size, big_endian>
+        (this->buffer_ + this->header_size_ + index * this->entry_size_);
+  }
+
+  Incremental_inputs_archive_header_write<size, big_endian>
+  get_archive_writer(size_t offset)
+  {
+    return Incremental_inputs_archive_header_write<size, big_endian>
+        (this->buffer_ + offset);
+  }
+
+  unsigned char*
+  get_archive_buffer(size_t offset)
+  {
+    return this->buffer_ + offset;
+  }
+
+ private:
+  size_t get_common_size()
+  {
+    size_t file_count = this->script_count_ + this->archive_count_ +
+      this->object_count_ + this->archive_member_count_;
+    return file_count * this->entry_size_;
+  }
+
+  size_t archive_count_;
+  size_t archive_member_count_;
+  size_t object_count_;
+  size_t script_count_;
+
+  /* Mesured from the first archive, not from the start of the section. */
+  size_t current_archive_offset_;
+  unsigned char *buffer_;
+
+  static const int entry_size_ =
+      Incremental_inputs_entry_write<size, big_endian>::data_size;
+  static const int header_size_ =
+      Incremental_inputs_header_write<size, big_endian>::data_size;
+  static const int archive_header_size_ =
+      Incremental_inputs_archive_header_write<size, big_endian>::data_size;
+  static const int archive_member_size_ =
+      Incremental_inputs_archive_member_write<size, big_endian>::data_size;
+};
+
 // Sized creation of .gnu_incremental_inputs section.
 
 template<int size, bool big_endian>
 Output_section_data*
 Incremental_inputs::sized_create_inputs_section_data()
 {
-  const int entry_size =
-      Incremental_inputs_entry_write<size, big_endian>::data_size;
-  const int header_size =
-      Incremental_inputs_header_write<size, big_endian>::data_size;
+  Incremental_inputs_write<size, big_endian> writer;
+  for (Inputs_info_map::const_iterator it = this->inputs_map_.begin();
+       it != this->inputs_map_.end();
+       ++it)
+    {
+      switch (it->second.type)
+        {
+        case INCREMENTAL_INPUT_SCRIPT:
+          writer.add_script();
+          break;
+        case INCREMENTAL_INPUT_ARCHIVE:
+          writer.add_archive(it->second.archive.member_count);
+          break;
+        case INCREMENTAL_INPUT_OBJECT:
+        case INCREMENTAL_INPUT_SHARED_LIBRARY:
+          writer.add_object();
+          break;
+        default:
+          gold_unreachable();
+        }
+    }
 
-  unsigned int sz = header_size + entry_size * this->inputs_map_.size();
-  unsigned char* buffer = new unsigned char[sz];
-  unsigned char* inputs_base = buffer + header_size;
+  writer.allocate();
 
-  Incremental_inputs_header_write<size, big_endian> header_writer(buffer);
+  Incremental_inputs_header_write<size, big_endian> header_writer =
+      writer.get_header_writer();
   gold_assert(this->command_line_key_ > 0);
   int cmd_offset = this->strtab_->get_offset_from_key(this->command_line_key_);
 
@@ -644,23 +877,44 @@ Incremental_inputs::sized_create_inputs_section_data()
     {
       gold_assert(it->second.index < this->inputs_map_.size());
 
-      unsigned char* entry_buffer =
-          inputs_base + it->second.index * entry_size;
-      Incremental_inputs_entry_write<size, big_endian> entry(entry_buffer);
+      Incremental_inputs_entry_write<size, big_endian> entry =
+          writer.get_entry_writer(it->second.index);
       int filename_offset =
           this->strtab_->get_offset_from_key(it->second.filename_key);
       entry.put_filename_offset(filename_offset);
-      // TODO: add per input data and timestamp.  Currently we store
-      // an out-of-bounds offset for future version of gold to reject
-      // such an incremental_inputs section.
-      entry.put_data_offset(0xffffffff);
+      switch (it->second.type)
+        {
+        case INCREMENTAL_INPUT_SCRIPT:
+          entry.put_data_offset(0);
+          break;
+        case INCREMENTAL_INPUT_ARCHIVE:
+          {
+            Archive_info archive = it->second.archive;
+            size_t archive_offset =
+              writer.get_current_archive_offset(archive.member_count);
+            entry.put_data_offset(archive_offset);
+            Incremental_inputs_archive_header_write<size, big_endian>
+                archive_header = writer.get_archive_writer(archive_offset);
+            archive_header.put_member_count(archive.member_count);
+          }
+          break;
+        case INCREMENTAL_INPUT_OBJECT:
+        case INCREMENTAL_INPUT_SHARED_LIBRARY:
+          // TODO: add per input data.  Currently we store
+          // an out-of-bounds offset for future version of gold to reject
+          // such an incremental_inputs section.
+          entry.put_data_offset(0xffffffff);
+          break;
+        default:
+          gold_unreachable();
+        }
       entry.put_timestamp_sec(it->second.mtime.seconds);
       entry.put_timestamp_nsec(it->second.mtime.nanoseconds);
       entry.put_input_type(it->second.type);
       entry.put_reserved(0);
     }
 
-  return new Output_data_const_buffer(buffer, sz, 8,
+  return new Output_data_const_buffer(writer.get_buffer(), writer.get_size(), 8,
 				      "** incremental link inputs list");
 }
 
diff --git a/gold/incremental.h b/gold/incremental.h
index f6e36fa..7c9c460 100644
--- a/gold/incremental.h
+++ b/gold/incremental.h
@@ -91,6 +91,24 @@ struct Incremental_inputs_entry_data
   elfcpp::Elf_Half reserved;
 };
 
+// Data stored in .gnu_incremental_input after the input entries
+// for each of the inputs with type INCREMENTAL_INPUT_ARCHIVE.
+struct Incremental_inputs_archive_header_data
+{
+  // Number of members in this archive.
+  elfcpp::Elf_Word member_count;
+};
+
+// Data stored in .gnu_incremental_input for each of the members of an archive.
+struct Incremental_inputs_archive_member_data
+{
+  // Offset of data in .gnu_incremental_input.
+  elfcpp::Elf_Word data_offset;
+
+  // Padding.
+  elfcpp::Elf_Word reserved;
+};
+
 // An object representing the ELF file we edit during an incremental build.
 // Similar to Object or Dynobj, but operates on Output_file and contains
 // method specific to file edition (TBD). This is the abstract parent class
@@ -323,12 +341,17 @@ class Incremental_inputs
 		  Input_argument_list::const_iterator end,
 		  unsigned int* index);
 
+  struct Archive_info
+  {
+    size_t member_count;
+  };
+
   // Additional data about an input needed for an incremental link.
   // None of these pointers is owned by the structure.
   struct Input_info
   {
     Input_info()
-      : type(INCREMENTAL_INPUT_INVALID), archive(NULL), filename_key(0),
+      : type(INCREMENTAL_INPUT_INVALID), archive(), filename_key(0),
         index(0)
     { }
 
@@ -338,7 +361,7 @@ class Incremental_inputs
     union
     {
       // Present if type == INCREMENTAL_INPUT_ARCHIVE.
-      Archive* archive;
+      struct Archive_info archive;
 
       // Present if type == INCREMENTAL_INPUT_OBJECT or
       // INCREMENTAL_INPUT_SHARED_LIBRARY.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]