New drop, with first cut of section layout code.
authorIan Lance Taylor <iant@google.com>
Thu, 21 Sep 2006 22:13:18 +0000 (22:13 +0000)
committerIan Lance Taylor <iant@google.com>
Thu, 21 Sep 2006 22:13:18 +0000 (22:13 +0000)
19 files changed:
gold/Makefile.am
gold/Makefile.in
gold/fileread.h
gold/gold.cc
gold/layout.cc [new file with mode: 0644]
gold/layout.h [new file with mode: 0644]
gold/object.cc
gold/object.h
gold/options.h
gold/output.cc [new file with mode: 0644]
gold/output.h [new file with mode: 0644]
gold/po/POTFILES.in
gold/po/gold.pot
gold/readsyms.cc
gold/readsyms.h
gold/stringpool.cc
gold/symtab.h
gold/targetsize.h [deleted file]
gold/workqueue.h

index a01aef4..ed26af9 100644 (file)
@@ -22,8 +22,10 @@ CCFILES = \
        fileread.cc \
        gold.cc \
        gold-threads.cc \
+       layout.cc \
        object.cc \
        options.cc \
+       output.cc \
        readsyms.cc \
        resolve.cc \
        symtab.cc \
@@ -36,13 +38,14 @@ HFILES = \
        fileread.h \
        gold.h \
        gold-threads.h \
+       layout.h \
        object.h \
        options.h \
+       output.h \
        readsyms.h \
        stringpool.h \
        symtab.h \
        target.h \
-       targetsize.h \
        target-select.h \
        workqueue.h
 
index 8881517..6dba59c 100644 (file)
@@ -66,10 +66,10 @@ CONFIG_HEADER = config.h
 CONFIG_CLEAN_FILES = po/Makefile.in
 PROGRAMS = $(noinst_PROGRAMS)
 am__objects_1 = dirsearch.$(OBJEXT) fileread.$(OBJEXT) gold.$(OBJEXT) \
-       gold-threads.$(OBJEXT) object.$(OBJEXT) options.$(OBJEXT) \
-       readsyms.$(OBJEXT) resolve.$(OBJEXT) symtab.$(OBJEXT) \
-       stringpool.$(OBJEXT) target-select.$(OBJEXT) \
-       workqueue.$(OBJEXT)
+       gold-threads.$(OBJEXT) layout.$(OBJEXT) object.$(OBJEXT) \
+       options.$(OBJEXT) output.$(OBJEXT) readsyms.$(OBJEXT) \
+       resolve.$(OBJEXT) symtab.$(OBJEXT) stringpool.$(OBJEXT) \
+       target-select.$(OBJEXT) workqueue.$(OBJEXT)
 am__objects_2 =
 am__objects_3 = i386.$(OBJEXT)
 am_ld_new_OBJECTS = $(am__objects_1) $(am__objects_2) $(am__objects_3)
@@ -233,8 +233,10 @@ CCFILES = \
        fileread.cc \
        gold.cc \
        gold-threads.cc \
+       layout.cc \
        object.cc \
        options.cc \
+       output.cc \
        readsyms.cc \
        resolve.cc \
        symtab.cc \
@@ -247,13 +249,14 @@ HFILES = \
        fileread.h \
        gold.h \
        gold-threads.h \
+       layout.h \
        object.h \
        options.h \
+       output.h \
        readsyms.h \
        stringpool.h \
        symtab.h \
        target.h \
-       targetsize.h \
        target-select.h \
        workqueue.h
 
@@ -340,8 +343,10 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gold-threads.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gold.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/i386.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/layout.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/object.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/options.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/output.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/readsyms.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/resolve.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stringpool.Po@am__quote@
index 2181485..b65a86b 100644 (file)
@@ -173,22 +173,6 @@ class File_view
   const unsigned char* data_;
 };
 
-// An object which locks a file using RAII.
-
-class File_read_lock
-{
- public:
-  File_read_lock(File_read& file)
-    : file_(file)
-  { this->file_.lock(); }
-
-  ~File_read_lock()
-  { this->file_.unlock(); }
-
- private:
-  File_read& file_;
-};
-
 // All the information we hold for a single input file.  This can be
 // an object file, a shared library, or an archive.
 
index e419f9c..02e7366 100644 (file)
@@ -12,6 +12,7 @@
 #include "dirsearch.h"
 #include "readsyms.h"
 #include "symtab.h"
+#include "layout.h"
 
 namespace gold
 {
@@ -66,7 +67,8 @@ void
 queue_initial_tasks(const General_options& options,
                    const Dirsearch& search_path,
                    const Command_line::Input_argument_list& inputs,
-                   Workqueue* workqueue, Symbol_table* symtab)
+                   Workqueue* workqueue, Object_list* input_objects,
+                   Symbol_table* symtab)
 {
   if (inputs.empty())
     gold_fatal(_("no input files"), false);
@@ -82,12 +84,13 @@ queue_initial_tasks(const General_options& options,
     {
       Task_token* next_blocker = new Task_token();
       next_blocker->add_blocker();
-      workqueue->queue(new Read_symbols(options, symtab, search_path,
-                                       *p, this_blocker, next_blocker));
+      workqueue->queue(new Read_symbols(options, input_objects, symtab,
+                                       search_path, *p, this_blocker,
+                                       next_blocker));
       this_blocker = next_blocker;
     }
 
-  // workqueue->queue(new Layout(options, inputs, this_blocker));
+  workqueue->queue(new Layout_task(options, input_objects, this_blocker));
 }
 
 } // end anonymous namespace.
@@ -113,6 +116,9 @@ main(int argc, char** argv)
   // The work queue.
   gold::Workqueue workqueue(command_line.options());
 
+  // The list of input objects.
+  Object_list input_objects;
+
   // The symbol table.
   Symbol_table symtab;
 
@@ -122,7 +128,8 @@ main(int argc, char** argv)
 
   // Queue up the first set of tasks.
   queue_initial_tasks(command_line.options(), search_path,
-                     command_line.inputs(), &workqueue, &symtab);
+                     command_line.inputs(), &workqueue, &input_objects,
+                     &symtab);
 
   // Run the main task processing loop.
   workqueue.process();
diff --git a/gold/layout.cc b/gold/layout.cc
new file mode 100644 (file)
index 0000000..3faec94
--- /dev/null
@@ -0,0 +1,432 @@
+// layout.cc -- lay out output file sections for gold
+
+#include "gold.h"
+
+#include <cassert>
+#include <cstring>
+#include <iostream>
+#include <utility>
+
+#include "output.h"
+#include "layout.h"
+
+namespace gold
+{
+
+// Layout_task methods.
+
+Layout_task::~Layout_task()
+{
+}
+
+// This task can be run when it is unblocked.
+
+Task::Is_runnable_type
+Layout_task::is_runnable(Workqueue*)
+{
+  if (this->this_blocker_->is_blocked())
+    return IS_BLOCKED;
+  return IS_RUNNABLE;
+}
+
+// We don't need to hold any locks for the duration of this task.  In
+// fact this task will be the only one running.
+
+Task_locker*
+Layout_task::locks(Workqueue*)
+{
+  return NULL;
+}
+
+// Lay out the sections.  This is called after all the input objects
+// have been read.
+
+void
+Layout_task::run(Workqueue*)
+{
+  Layout layout(this->options_);
+  for (Object_list::const_iterator p = this->input_objects_->begin();
+       p != this->input_objects_->end();
+       ++p)
+    (*p)->layout(&layout);
+}
+
+// Layout methods.
+
+// Hash a key we use to look up an output section mapping.
+
+size_t
+Layout::Hash_key::operator()(const Layout::Key& k) const
+{
+ return reinterpret_cast<size_t>(k.first) + k.second.first + k.second.second;
+}
+
+// Whether to include this section in the link.
+
+template<int size, bool big_endian>
+bool
+Layout::include_section(Object*, const char*,
+                       const elfcpp::Shdr<size, big_endian>& shdr)
+{
+  // Some section types are never linked.  Some are only linked when
+  // doing a relocateable link.
+  switch (shdr.get_sh_type())
+    {
+    case elfcpp::SHT_NULL:
+    case elfcpp::SHT_SYMTAB:
+    case elfcpp::SHT_DYNSYM:
+    case elfcpp::SHT_STRTAB:
+    case elfcpp::SHT_HASH:
+    case elfcpp::SHT_DYNAMIC:
+    case elfcpp::SHT_SYMTAB_SHNDX:
+      return false;
+
+    case elfcpp::SHT_RELA:
+    case elfcpp::SHT_REL:
+    case elfcpp::SHT_GROUP:
+      return this->options_.is_relocatable();
+
+    default:
+      // FIXME: Handle stripping debug sections here.
+      return true;
+    }
+}
+
+// Return the output section to use for input section NAME, with
+// header HEADER, from object OBJECT.  Set *OFF to the offset of this
+// input section without the output section.
+
+template<int size, bool big_endian>
+Output_section*
+Layout::layout(Object* object, const char* name,
+              const elfcpp::Shdr<size, big_endian>& shdr, off_t* off)
+{
+  if (!this->include_section(object, name, shdr))
+    return NULL;
+
+  // Unless we are doing a relocateable link, .gnu.linkonce sections
+  // are laid out as though they were named for the sections are
+  // placed into.
+  if (!this->options_.is_relocatable() && Layout::is_linkonce(name))
+    name = Layout::linkonce_output_name(name);
+
+  // FIXME: Handle SHF_OS_NONCONFORMING here.
+
+  // Canonicalize the section name.
+  name = this->namepool_.add(name);
+
+  // Find the output section.  The output section is selected based on
+  // the section name, type, and flags.
+
+  // FIXME: If we want to do relaxation, we need to modify this
+  // algorithm.  We also build a list of input sections for each
+  // output section.  Then we relax all the input sections.  Then we
+  // walk down the list and adjust all the offsets.
+
+  elfcpp::Elf_Word type = shdr.get_sh_type();
+  elfcpp::Elf_Xword flags = shdr.get_sh_flags();
+  const Key key(name, std::make_pair(type, flags));
+  const std::pair<Key, Output_section*> v(key, NULL);
+  std::pair<Section_name_map::iterator, bool> ins(
+    this->section_name_map_.insert(v));
+
+  Output_section* os;
+  if (!ins.second)
+    os = ins.first->second;
+  else
+    {
+      // This is the first time we've seen this name/type/flags
+      // combination.
+      os = this->make_output_section(name, type, flags);
+      ins.first->second = os;
+    }
+
+  // FIXME: Handle SHF_LINK_ORDER somewhere.
+
+  *off = os->add_input_section(object, name, shdr);
+
+  return os;
+}
+
+// Return whether SEG1 should be before SEG2 in the output file.  This
+// is based entirely on the segment type and flags.  When this is
+// called the segment addresses has normally not yet been set.
+
+bool
+Layout::segment_precedes(const Output_segment* seg1,
+                        const Output_segment* seg2)
+{
+  elfcpp::Elf_Word type1 = seg1->type();
+  elfcpp::Elf_Word type2 = seg2->type();
+
+  // The single PT_PHDR segment is required to precede any loadable
+  // segment.  We simply make it always first.
+  if (type1 == elfcpp::PT_PHDR)
+    {
+      assert(type2 != elfcpp::PT_PHDR);
+      return true;
+    }
+  if (type2 == elfcpp::PT_PHDR)
+    return false;
+
+  // The single PT_INTERP segment is required to precede any loadable
+  // segment.  We simply make it always second.
+  if (type1 == elfcpp::PT_INTERP)
+    {
+      assert(type2 != elfcpp::PT_INTERP);
+      return true;
+    }
+  if (type2 == elfcpp::PT_INTERP)
+    return false;
+
+  // We then put PT_LOAD segments before any other segments.
+  if (type1 == elfcpp::PT_LOAD && type2 != elfcpp::PT_LOAD)
+    return true;
+  if (type2 == elfcpp::PT_LOAD && type1 != elfcpp::PT_LOAD)
+    return false;
+
+  const elfcpp::Elf_Word flags1 = seg1->flags();
+  const elfcpp::Elf_Word flags2 = seg2->flags();
+
+  // The order of non-PT_LOAD segments is unimportant.  We simply sort
+  // by the numeric segment type and flags values.  There should not
+  // be more than one segment with the same type and flags.
+  if (type1 != elfcpp::PT_LOAD)
+    {
+      if (type1 != type2)
+       return type1 < type2;
+      assert(flags1 != flags2);
+      return flags1 < flags2;
+    }
+
+  // We sort PT_LOAD segments based on the flags.  Readonly segments
+  // come before writable segments.  Then executable segments come
+  // before non-executable segments.  Then the unlikely case of a
+  // non-readable segment comes before the normal case of a readable
+  // segment.  If there are multiple segments with the same type and
+  // flags, we require that the address be set, and we sort by
+  // virtual address and then physical address.
+  if ((flags1 & elfcpp::PF_W) != (flags2 & elfcpp::PF_W))
+    return (flags1 & elfcpp::PF_W) == 0;
+  if ((flags1 & elfcpp::PF_X) != (flags2 & elfcpp::PF_X))
+    return (flags1 & elfcpp::PF_X) != 0;
+  if ((flags1 & elfcpp::PF_R) != (flags2 & elfcpp::PF_R))
+    return (flags1 & elfcpp::PF_R) == 0;
+
+  uint64_t vaddr1 = seg1->vaddr();
+  uint64_t vaddr2 = seg2->vaddr();
+  if (vaddr1 != vaddr2)
+    return vaddr1 < vaddr2;
+
+  uint64_t paddr1 = seg1->paddr();
+  uint64_t paddr2 = seg2->paddr();
+  assert(paddr1 != paddr2);
+  return paddr1 < paddr2;
+}
+
+// Map section flags to segment flags.
+
+elfcpp::Elf_Word
+Layout::section_flags_to_segment(elfcpp::Elf_Xword flags)
+{
+  elfcpp::Elf_Word ret = elfcpp::PF_R;
+  if ((flags & elfcpp::SHF_WRITE) != 0)
+    ret |= elfcpp::PF_W;
+  if ((flags & elfcpp::SHF_EXECINSTR) != 0)
+    ret |= elfcpp::PF_X;
+  return ret;
+}
+
+// Make a new Output_section, and attach it to segments as
+// appropriate.
+
+Output_section*
+Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
+                           elfcpp::Elf_Xword flags)
+{
+  Output_section* os = new Output_section(name, type, flags);
+
+  if ((flags & elfcpp::SHF_ALLOC) == 0)
+    this->section_list_.push_back(os);
+  else
+    {
+      // This output section goes into a PT_LOAD segment.
+
+      elfcpp::Elf_Word seg_flags = Layout::section_flags_to_segment(flags);
+
+      // The only thing we really care about for PT_LOAD segments is
+      // whether or not they are writable, so that is how we search
+      // for them.  People who need segments sorted on some other
+      // basis will have to wait until we implement a mechanism for
+      // them to describe the segments they want.
+
+      Segment_list::const_iterator p;
+      for (p = this->segment_list_.begin();
+          p != this->segment_list_.end();
+          ++p)
+       {
+         if ((*p)->type() == elfcpp::PT_LOAD
+             && ((*p)->flags() & elfcpp::PF_W) == (seg_flags & elfcpp::PF_W))
+           {
+             (*p)->add_output_section(os);
+             if ((*p)->flags() != seg_flags)
+               (*p)->update_flags(seg_flags);
+             break;
+           }
+       }
+
+      if (p == this->segment_list_.end())
+       {
+         Output_segment* oseg = new Output_segment(elfcpp::PT_LOAD,
+                                                   seg_flags);
+         this->segment_list_.push_back(oseg);
+         oseg->add_output_section(os);
+       }
+
+      // If we see a loadable SHT_NOTE section, we create a PT_NOTE
+      // segment.
+      if (type == elfcpp::SHT_NOTE)
+       {
+         // See if we already have an equivalent PT_NOTE segment.
+         for (p = this->segment_list_.begin();
+              p != segment_list_.end();
+              ++p)
+           {
+             if ((*p)->type() == elfcpp::PT_NOTE
+                 && (((*p)->flags() & elfcpp::PF_W)
+                     == (seg_flags & elfcpp::PF_W)))
+               {
+                 (*p)->add_output_section(os);
+                 if ((*p)->flags() != seg_flags)
+                   (*p)->update_flags(seg_flags);
+                 break;
+               }
+           }
+
+         if (p == this->segment_list_.end())
+           {
+             Output_segment* oseg = new Output_segment(elfcpp::PT_NOTE,
+                                                       seg_flags);
+             this->segment_list_.push_back(oseg);
+             oseg->add_output_section(os);
+           }
+       }
+    }
+
+  return os;
+}
+
+// The mapping of .gnu.linkonce section names to real section names.
+
+#define MAPPING_INIT(f, t) { f, sizeof(f) - 1, t }
+const Layout::Linkonce_mapping Layout::linkonce_mapping[] =
+{
+  MAPPING_INIT("d.rel.ro", ".data.rel.ro"),    // Must be before "d".
+  MAPPING_INIT("t", ".text"),
+  MAPPING_INIT("r", ".rodata"),
+  MAPPING_INIT("d", ".data"),
+  MAPPING_INIT("b", ".bss"),
+  MAPPING_INIT("s", ".sdata"),
+  MAPPING_INIT("sb", ".sbss"),
+  MAPPING_INIT("s2", ".sdata2"),
+  MAPPING_INIT("sb2", ".sbss2"),
+  MAPPING_INIT("wi", ".debug_info"),
+  MAPPING_INIT("td", ".tdata"),
+  MAPPING_INIT("tb", ".tbss"),
+  MAPPING_INIT("lr", ".lrodata"),
+  MAPPING_INIT("l", ".ldata"),
+  MAPPING_INIT("lb", ".lbss"),
+};
+#undef MAPPING_INIT
+
+const int Layout::linkonce_mapping_count =
+  sizeof(Layout::linkonce_mapping) / sizeof(Layout::linkonce_mapping[0]);
+
+// Return the name of the output section to use for a .gnu.linkonce
+// section.  This is based on the default ELF linker script of the old
+// GNU linker.  For example, we map a name like ".gnu.linkonce.t.foo"
+// to ".text".
+
+const char*
+Layout::linkonce_output_name(const char* name)
+{
+  const char* s = name + sizeof(".gnu.linkonce") - 1;
+  if (*s != '.')
+    return name;
+  ++s;
+  const Linkonce_mapping* plm = linkonce_mapping;
+  for (int i = 0; i < linkonce_mapping_count; ++i, ++plm)
+    {
+      if (strncmp(s, plm->from, plm->fromlen) == 0 && s[plm->fromlen] == '.')
+       return plm->to;
+    }
+  return name;
+}
+
+// Record the signature of a comdat section, and return whether to
+// include it in the link.  If GROUP is true, this is a regular
+// section group.  If GROUP is false, this is a group signature
+// derived from the name of a linkonce section.  We want linkonce
+// signatures and group signatures to block each other, but we don't
+// want a linkonce signature to block another linkonce signature.
+
+bool
+Layout::add_comdat(const char* signature, bool group)
+{
+  std::string sig(signature);
+  std::pair<Signatures::iterator, bool> ins(
+    this->signatures_.insert(std::make_pair(signature, group)));
+
+  if (ins.second)
+    {
+      // This is the first time we've seen this signature.
+      return true;
+    }
+
+  if (ins.first->second)
+    {
+      // We've already seen a real section group with this signature.
+      return false;
+    }
+  else if (group)
+    {
+      // This is a real section group, and we've already seen a
+      // linkonce section with tihs signature.  Record that we've seen
+      // a section group, and don't include this section group.
+      ins.first->second = true;
+      return false;
+    }
+  else
+    {
+      // We've already seen a linkonce section and this is a linkonce
+      // section.  These don't block each other--this may be the same
+      // symbol name with different section types.
+      return true;
+    }
+}
+
+// Instantiate the templates we need.  We could use the configure
+// script to restrict this to only the ones for implemented targets.
+
+template
+Output_section*
+Layout::layout<32, false>(Object* object, const char* name,
+                         const elfcpp::Shdr<32, false>& shdr, off_t*);
+
+template
+Output_section*
+Layout::layout<32, true>(Object* object, const char* name,
+                        const elfcpp::Shdr<32, true>& shdr, off_t*);
+
+template
+Output_section*
+Layout::layout<64, false>(Object* object, const char* name,
+                         const elfcpp::Shdr<64, false>& shdr, off_t*);
+
+template
+Output_section*
+Layout::layout<64, true>(Object* object, const char* name,
+                        const elfcpp::Shdr<64, true>& shdr, off_t*);
+
+
+} // End namespace gold.
diff --git a/gold/layout.h b/gold/layout.h
new file mode 100644 (file)
index 0000000..77fdfc2
--- /dev/null
@@ -0,0 +1,181 @@
+// layout.h -- lay out output file sections for gold  -*- C++ -*-
+
+#ifndef GOLD_LAYOUT_H
+#define GOLD_LAYOUT_H
+
+#include <list>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "options.h"
+#include "workqueue.h"
+#include "object.h"
+#include "stringpool.h"
+
+namespace gold
+{
+
+class Output_section;
+class Output_segment;
+
+// This Task handles mapping the input sections to output sections and
+// laying them out in memory.
+
+class Layout_task : public Task
+{
+ public:
+  // OPTIONS is the command line options, INPUT_OBJECTS is the list of
+  // input objects, THIS_BLOCKER is a token which blocks this task
+  // from executing until all the input symbols have been read.
+  Layout_task(const General_options& options, const Object_list* input_objects,
+             Task_token* this_blocker)
+    : options_(options), input_objects_(input_objects),
+      this_blocker_(this_blocker)
+  { }
+
+  ~Layout_task();
+
+  // The standard Task methods.
+
+  Is_runnable_type
+  is_runnable(Workqueue*);
+
+  Task_locker*
+  locks(Workqueue*);
+
+  void
+  run(Workqueue*);
+
+ private:
+  Layout_task(const Layout_task&);
+  Layout_task& operator=(const Layout_task&);
+
+  const General_options& options_;
+  const Object_list* input_objects_;
+  Task_token* this_blocker_;
+};
+
+// This class handles the details of laying out input sections.
+
+class Layout
+{
+ public:
+  Layout(const General_options& options)
+    : options_(options), namepool_(), signatures_(),
+      section_name_map_(), segment_list_()
+  { }
+
+  // Given an input section named NAME with data in SHDR from the
+  // object file OBJECT, return the output section where this input
+  // section should go.  Set *OFFSET to the offset within the output
+  // section.
+  template<int size, bool big_endian>
+  Output_section*
+  layout(Object *object, const char* name,
+        const elfcpp::Shdr<size, big_endian>& shdr, off_t* offset);
+
+  // Return whether a section is a .gnu.linkonce section, given the
+  // section name.
+  static inline bool
+  is_linkonce(const char* name)
+  { return strncmp(name, ".gnu.linkonce", sizeof(".gnu.linkonce") - 1) == 0; }
+
+  // Record the signature of a comdat section, and return whether to
+  // include it in the link.  The GROUP parameter is true for a
+  // section group signature, false for a signature derived from a
+  // .gnu.linkonce section.
+  bool
+  add_comdat(const char*, bool group);
+
+ private:
+  Layout(const Layout&);
+  Layout& operator=(const Layout&);
+
+  // Mapping from .gnu.linkonce section names to output section names.
+  struct Linkonce_mapping
+  {
+    const char* from;
+    int fromlen;
+    const char* to;
+  };
+  static const Linkonce_mapping linkonce_mapping[];
+  static const int linkonce_mapping_count;
+
+  // Return whether to include this section in the link.
+  template<int size, bool big_endian>
+  bool
+  include_section(Object* object, const char* name,
+                 const elfcpp::Shdr<size, big_endian>&);
+
+  // Return the output section name to use for a linkonce section
+  // name.
+  static const char*
+  linkonce_output_name(const char* name);
+
+  // Create a new Output_section.
+  Output_section*
+  make_output_section(const char* name, elfcpp::Elf_Word type,
+                     elfcpp::Elf_Xword flags);
+
+  // Return whether SEG1 comes before SEG2 in the output file.
+  static bool
+  Layout::segment_precedes(const Output_segment* seg1,
+                          const Output_segment* seg2);
+
+  // Map from section flags to segment flags.
+  static elfcpp::Elf_Word
+  section_flags_to_segment(elfcpp::Elf_Xword flags);
+
+  // A mapping used for group signatures.
+  typedef Unordered_map<std::string, bool> Signatures;
+
+  // Mapping from input section name/type/flags to output section.  We
+  // use canonicalized strings here.
+
+  typedef std::pair<const char*,
+                   std::pair<elfcpp::Elf_Word, elfcpp::Elf_Xword> > Key;
+
+  struct Hash_key
+  {
+    size_t
+    operator()(const Key& k) const;
+  };
+
+  typedef Unordered_map<Key, Output_section*, Hash_key> Section_name_map;
+
+  // A comparison class for segments.
+
+  struct Compare_segments
+  {
+    bool
+    operator()(const Output_segment* seg1, const Output_segment* seg2)
+    { return Layout::segment_precedes(seg1, seg2); }
+  };
+
+  // The list of segments.
+
+  typedef std::list<Output_segment*> Segment_list;
+
+  // The list of sections not attached to a segment.
+
+  typedef std::list<Output_section*> Section_list;
+
+  // A reference to the options on the command line.
+  const General_options& options_;
+  // The output section names.
+  Stringpool namepool_;
+  // The list of group sections and linkonce sections which we have seen.
+  Signatures signatures_;
+  // The mapping from input section name/type/flags to output sections.
+  Section_name_map section_name_map_;
+  // The list of output segments.
+  Segment_list segment_list_;
+  // The list of output sections which are not attached to any output
+  // segment.
+  Section_list section_list_;
+};
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_LAYOUT_H)
index bad7f47..0e00c43 100644 (file)
@@ -8,6 +8,7 @@
 
 #include "object.h"
 #include "target-select.h"
+#include "layout.h"
 
 namespace gold
 {
@@ -42,28 +43,24 @@ Sized_object<size, big_endian>::Sized_object(
     off_t offset,
     const elfcpp::Ehdr<size, big_endian>& ehdr)
   : Object(name, input_file, false, offset),
-    osabi_(ehdr.get_e_ident()[elfcpp::EI_OSABI]),
-    abiversion_(ehdr.get_e_ident()[elfcpp::EI_ABIVERSION]),
-    machine_(ehdr.get_e_machine()),
     flags_(ehdr.get_e_flags()),
     shoff_(ehdr.get_e_shoff()),
-    shnum_(0),
     shstrndx_(0),
     symtab_shnum_(0),
     symbols_(NULL)
 {
-  if (ehdr.get_e_ehsize() != elfcpp::Elf_sizes<size>::ehdr_size)
+  if (ehdr.get_e_ehsize() != This::ehdr_size)
     {
       fprintf(stderr, _("%s: %s: bad e_ehsize field (%d != %d)\n"),
              program_name, this->name().c_str(), ehdr.get_e_ehsize(),
-             elfcpp::Elf_sizes<size>::ehdr_size);
+             This::ehdr_size);
       gold_exit(false);
     }
-  if (ehdr.get_e_shentsize() != elfcpp::Elf_sizes<size>::shdr_size)
+  if (ehdr.get_e_shentsize() != This::shdr_size)
     {
       fprintf(stderr, _("%s: %s: bad e_shentsize field (%d != %d)\n"),
              program_name, this->name().c_str(), ehdr.get_e_shentsize(),
-             elfcpp::Elf_sizes<size>::shdr_size);
+             This::shdr_size);
       gold_exit(false);
     }
 }
@@ -81,12 +78,14 @@ void
 Sized_object<size, big_endian>::setup(
     const elfcpp::Ehdr<size, big_endian>& ehdr)
 {
-  Target* target = select_target(this->machine_, size, big_endian,
-                                this->osabi_, this->abiversion_);
+  int machine = ehdr.get_e_machine();
+  Target* target = select_target(machine, size, big_endian,
+                                ehdr.get_e_ident()[elfcpp::EI_OSABI],
+                                ehdr.get_e_ident()[elfcpp::EI_ABIVERSION]);
   if (target == NULL)
     {
       fprintf(stderr, _("%s: %s: unsupported ELF machine number %d\n"),
-             program_name, this->name().c_str(), this->machine_);
+             program_name, this->name().c_str(), machine);
       gold_exit(false);
     }
   this->set_target(target);
@@ -95,25 +94,24 @@ Sized_object<size, big_endian>::setup(
   if ((shnum == 0 || shstrndx == elfcpp::SHN_XINDEX)
       && this->shoff_ != 0)
     {
-      const unsigned char* p = this->get_view
-       (this->shoff_, elfcpp::Elf_sizes<size>::shdr_size);
+      const unsigned char* p = this->get_view (this->shoff_, This::shdr_size);
       elfcpp::Shdr<size, big_endian> shdr(p);
       if (shnum == 0)
        shnum = shdr.get_sh_size();
       if (shstrndx == elfcpp::SHN_XINDEX)
        shstrndx = shdr.get_sh_link();
     }
-  this->shnum_ = shnum;
+  this->set_shnum(shnum);
   this->shstrndx_ = shstrndx;
 
   if (shnum == 0)
     return;
 
   // Find the SHT_SYMTAB section.
-  const unsigned char* p = this->get_view
-    (this->shoff_, shnum * elfcpp::Elf_sizes<size>::shdr_size);
+  const unsigned char* p = this->get_view (this->shoff_,
+                                          shnum * This::shdr_size);
   // Skip the first section, which is always empty.
-  p += elfcpp::Elf_sizes<size>::shdr_size;
+  p += This::shdr_size;
   for (unsigned int i = 1; i < shnum; ++i)
     {
       elfcpp::Shdr<size, big_endian> shdr(p);
@@ -122,7 +120,7 @@ Sized_object<size, big_endian>::setup(
          this->symtab_shnum_ = i;
          break;
        }
-      p += elfcpp::Elf_sizes<size>::shdr_size;
+      p += This::shdr_size;
     }
 }
 
@@ -143,7 +141,7 @@ Sized_object<size, big_endian>::do_read_symbols()
       return ret;
     }
 
-  int shdr_size = elfcpp::Elf_sizes<size>::shdr_size;
+  const int shdr_size = This::shdr_size;
 
   // Read the symbol table section header.
   off_t symtabshdroff = this->shoff_ + (this->symtab_shnum_ * shdr_size);
@@ -152,7 +150,7 @@ Sized_object<size, big_endian>::do_read_symbols()
   assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
 
   // We only need the external symbols.
-  int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+  const int sym_size = This::sym_size;
   off_t locsize = symtabshdr.get_sh_info() * sym_size;
   off_t extoff = symtabshdr.get_sh_offset() + locsize;
   off_t extsize = symtabshdr.get_sh_size() - locsize;
@@ -162,7 +160,7 @@ Sized_object<size, big_endian>::do_read_symbols()
 
   // Read the section header for the symbol names.
   unsigned int strtab_shnum = symtabshdr.get_sh_link();
-  if (strtab_shnum == 0 || strtab_shnum >= this->shnum_)
+  if (strtab_shnum == 0 || strtab_shnum >= this->shnum())
     {
       fprintf(stderr, _("%s: %s: invalid symbol table name index: %u\n"),
              program_name, this->name().c_str(), strtab_shnum);
@@ -206,7 +204,7 @@ Sized_object<size, big_endian>::do_add_symbols(Symbol_table* symtab,
       return;
     }
 
-  unsigned int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+  const int sym_size = This::sym_size;
   size_t symcount = sd.symbols_size / sym_size;
   if (symcount * sym_size != sd.symbols_size)
     {
@@ -224,6 +222,226 @@ Sized_object<size, big_endian>::do_add_symbols(Symbol_table* symtab,
     reinterpret_cast<const char*>(sd.symbol_names->data());
   symtab->add_from_object(this, syms, symcount, sym_names, 
                          sd.symbol_names_size,  this->symbols_);
+
+  delete sd.symbols;
+  delete sd.symbol_names;
+}
+
+// Return whether to include a section group in the link.  LAYOUT is
+// used to keep track of which section groups we have already seen.
+// INDEX is the index of the section group and SHDR is the section
+// header.  If we do not want to include this group, we set bits in
+// OMIT for each section which should be discarded.
+
+template<int size, bool big_endian>
+bool
+Sized_object<size, big_endian>::include_section_group(
+    Layout* layout,
+    unsigned int index,
+    const elfcpp::Shdr<size, big_endian>& shdr,
+    std::vector<bool>* omit)
+{
+  // Read the section contents.
+  const unsigned char* pcon = this->get_view(shdr.get_sh_offset(),
+                                            shdr.get_sh_size());
+  const elfcpp::Elf_Word* pword =
+    reinterpret_cast<const elfcpp::Elf_Word*>(pcon);
+
+  // The first word contains flags.  We only care about COMDAT section
+  // groups.  Other section groups are always included in the link
+  // just like ordinary sections.
+  elfcpp::Elf_Word flags = elfcpp::read_elf_word<big_endian>(pword);
+  if ((flags & elfcpp::GRP_COMDAT) == 0)
+    return true;
+
+  // Look up the group signature, which is the name of a symbol.  This
+  // is a lot of effort to go to to read a string.  Why didn't they
+  // just use the name of the SHT_GROUP section as the group
+  // signature?
+
+  // Get the appropriate symbol table header (this will normally be
+  // the single SHT_SYMTAB section, but in principle it need not be).
+  if (shdr.get_sh_link() >= this->shnum())
+    {
+      fprintf(stderr, _("%s: %s: section group %u link %u out of range\n"),
+             program_name, this->name().c_str(), index, shdr.get_sh_link());
+      gold_exit(false);
+    }
+  off_t off = this->shoff_ + shdr.get_sh_link() * This::shdr_size;
+  const unsigned char* psymshdr = this->get_view(off, This::shdr_size);
+  elfcpp::Shdr<size, big_endian> symshdr(psymshdr);
+
+  // Read the symbol table entry.
+  if (shdr.get_sh_info() >= symshdr.get_sh_size() / This::sym_size)
+    {
+      fprintf(stderr, _("%s: %s: section group %u info %u out of range\n"),
+             program_name, this->name().c_str(), index, shdr.get_sh_info());
+      gold_exit(false);
+    }
+  off_t symoff = symshdr.get_sh_offset() + shdr.get_sh_info() * This::sym_size;
+  const unsigned char* psym = this->get_view(symoff, This::sym_size);
+  elfcpp::Sym<size, big_endian> sym(psym);
+
+  // Read the section header for the symbol table names.
+  if (symshdr.get_sh_link() >= this->shnum())
+    {
+      fprintf(stderr, _("%s; %s: symtab section %u link %u out of range\n"),
+             program_name, this->name().c_str(), shdr.get_sh_link(),
+             symshdr.get_sh_link());
+      gold_exit(false);
+    }
+  off_t symnameoff = this->shoff_ + symshdr.get_sh_link() * This::shdr_size;
+  const unsigned char* psymnamehdr = this->get_view(symnameoff,
+                                                   This::shdr_size);
+  elfcpp::Shdr<size, big_endian> symnamehdr(psymnamehdr);
+
+  // Read the symbol table names.
+  const unsigned char *psymnamesu = this->get_view(symnamehdr.get_sh_offset(),
+                                                  symnamehdr.get_sh_size());
+  const char* psymnames = reinterpret_cast<const char*>(psymnamesu);
+
+  // Get the section group signature.
+  if (sym.get_st_name() >= symnamehdr.get_sh_size())
+    {
+      fprintf(stderr, _("%s: %s: symbol %u name offset %u out of range\n"),
+             program_name, this->name().c_str(), shdr.get_sh_info(),
+             sym.get_st_name());
+      gold_exit(false);
+    }
+
+  const char* signature = psymnames + sym.get_st_name();
+
+  // Record this section group, and see whether we've already seen one
+  // with the same signature.
+  if (layout->add_comdat(signature, true))
+    return true;
+
+  // This is a duplicate.  We want to discard the sections in this
+  // group.
+  size_t count = shdr.get_sh_size() / sizeof(elfcpp::Elf_Word);
+  for (size_t i = 1; i < count; ++i)
+    {
+      elfcpp::Elf_Word secnum = elfcpp::read_elf_word<big_endian>(pword + i);
+      if (secnum >= this->shnum())
+       {
+         fprintf(stderr,
+                 _("%s: %s: section %u in section group %u out of range"),
+                 program_name, this->name().c_str(), secnum,
+                 index);
+         gold_exit(false);
+       }
+      (*omit)[secnum] = true;
+    }
+
+  return false;
+}
+
+// Whether to include a linkonce section in the link.  NAME is the
+// name of the section and SHDR is the section header.
+
+// Linkonce sections are a GNU extension implemented in the original
+// GNU linker before section groups were defined.  The semantics are
+// that we only include one linkonce section with a given name.  The
+// name of a linkonce section is normally .gnu.linkonce.T.SYMNAME,
+// where T is the type of section and SYMNAME is the name of a symbol.
+// In an attempt to make linkonce sections interact well with section
+// groups, we try to identify SYMNAME and use it like a section group
+// signature.  We want to block section groups with that signature,
+// but not other linkonce sections with that signature.  We also use
+// the full name of the linkonce section as a normal section group
+// signature.
+
+template<int size, bool big_endian>
+bool
+Sized_object<size, big_endian>::include_linkonce_section(
+    Layout* layout,
+    const char* name,
+    const elfcpp::Shdr<size, big_endian>&)
+{
+  const char* symname = strrchr(name, '.') + 1;
+  bool omit1 = layout->add_comdat(symname, false);
+  bool omit2 = layout->add_comdat(name, true);
+  return omit1 || omit2;
+}
+
+// Lay out the input sections.  We walk through the sections and check
+// whether they should be included in the link.  If they should, we
+// pass them to the Layout object, which will return an output section
+// and an offset.
+
+template<int size, bool big_endian>
+void
+Sized_object<size, big_endian>::do_layout(Layout* layout)
+{
+  // This is always called from the main thread.  Lock the file to
+  // keep the error checks happy.
+  Task_locker_obj<File_read> frl(this->input_file()->file());
+
+  // Get the section headers.
+  unsigned int shnum = this->shnum();
+  const unsigned char* pshdrs = this->get_view(this->shoff_,
+                                              shnum * This::shdr_size);
+
+  // Get the section names.
+  const unsigned char* pshdrnames = pshdrs + this->shstrndx_ * This::shdr_size;
+  elfcpp::Shdr<size, big_endian> shdrnames(pshdrnames);
+  typename elfcpp::Elf_types<size>::Elf_WXword names_size =
+    shdrnames.get_sh_size();
+  const unsigned char* pnamesu = this->get_view(shdrnames.get_sh_offset(),
+                                               shdrnames.get_sh_size());
+  const char* pnames = reinterpret_cast<const char*>(pnamesu);
+
+  std::vector<Map_to_output>& map_sections(this->map_to_output());
+  map_sections.reserve(shnum);
+
+  // Keep track of which sections to omit.
+  std::vector<bool> omit(shnum, false);
+
+  for (unsigned int i = 0; i < shnum; ++i)
+    {
+      elfcpp::Shdr<size, big_endian> shdr(pshdrs);
+
+      if (shdr.get_sh_name() >= names_size)
+       {
+         fprintf(stderr,
+                 _("%s: %s: bad section name offset for section %u: %lu\n"),
+                 program_name, this->name().c_str(), i,
+                 static_cast<unsigned long>(shdr.get_sh_name()));
+         gold_exit(false);
+       }
+
+      const char* name = pnames + shdr.get_sh_name();
+
+      bool discard = omit[i];
+      if (!discard)
+       {
+         if (shdr.get_sh_type() == elfcpp::SHT_GROUP)
+           {
+             if (!this->include_section_group(layout, i, shdr, &omit))
+               discard = true;
+           }
+         else if (Layout::is_linkonce(name))
+           {
+             if (!this->include_linkonce_section(layout, name, shdr))
+               discard = true;
+           }
+       }
+
+      if (discard)
+       {
+         // Do not include this section in the link.
+         map_sections[i].output_section = NULL;
+         continue;
+       }
+
+      off_t offset;
+      Output_section* os = layout->layout(this, name, shdr, &offset);
+
+      map_sections[i].output_section = os;
+      map_sections[i].offset = offset;
+
+      pshdrs += This::shdr_size;
+    }
 }
 
 } // End namespace gold.
index b0ee015..0026531 100644 (file)
@@ -4,6 +4,7 @@
 #define GOLD_OBJECT_H
 
 #include <cassert>
+#include <vector>
 
 #include "elfcpp.h"
 #include "fileread.h"
@@ -13,6 +14,9 @@
 namespace gold
 {
 
+class Output_section;
+class Layout;
+
 // Data to pass from read_symbols() to add_symbols().
 
 struct Read_symbols_data
@@ -42,7 +46,8 @@ class Object
   Object(const std::string& name, Input_file* input_file, bool is_dynamic,
         off_t offset = 0)
     : name_(name), input_file_(input_file), offset_(offset),
-      is_dynamic_(is_dynamic), target_(NULL)
+      shnum_(0), is_dynamic_(is_dynamic), target_(NULL),
+      map_to_output_()
   { }
 
   virtual ~Object()
@@ -58,21 +63,26 @@ class Object
   is_dynamic() const
   { return this->is_dynamic_; }
 
-  // Read the symbol and relocation information.
-  Read_symbols_data
-  read_symbols()
-  { return this->do_read_symbols(); }
-
-  // Add symbol information to the global symbol table.
-  void
-  add_symbols(Symbol_table* symtab, Read_symbols_data rd)
-  { this->do_add_symbols(symtab, rd); }
-
   // Return the target structure associated with this object.
   Target*
-  target()
+  target() const
   { return this->target_; }
 
+  // Lock the underlying file.
+  void
+  lock()
+  { this->input_file_->file().lock(); }
+
+  // Unlock the underlying file.
+  void
+  unlock()
+  { this->input_file_->file().unlock(); }
+
+  // Return whether the underlying file is locked.
+  bool
+  is_locked() const
+  { return this->input_file_->file().is_locked(); }
+
   // Return the sized target structure associated with this object.
   // This is like the target method but it returns a pointer of
   // appropriate checked type.
@@ -80,7 +90,35 @@ class Object
   Sized_target<size, big_endian>*
   sized_target();
 
+  // Read the symbol and relocation information.
+  Read_symbols_data
+  read_symbols()
+  { return this->do_read_symbols(); }
+
+  // Add symbol information to the global symbol table.
+  void
+  add_symbols(Symbol_table* symtab, Read_symbols_data rd)
+  { this->do_add_symbols(symtab, rd); }
+
+  // Pass sections which should be included in the link to the Layout
+  // object, and record where the sections go in the output file.
+  void
+  layout(Layout* lay)
+  { this->do_layout(lay); }
+
  protected:
+  // What we need to know to map an input section to an output
+  // section.  We keep an array of these, one for each input section,
+  // indexed by the input section number.
+  struct Map_to_output
+  {
+    // The output section.  This is NULL if the input section is to be
+    // discarded.
+    Output_section* output_section;
+    // The offset within the output section.
+    off_t offset;
+  };
+
   // Read the symbols--implemented by child class.
   virtual Read_symbols_data
   do_read_symbols() = 0;
@@ -90,6 +128,10 @@ class Object
   virtual void
   do_add_symbols(Symbol_table*, Read_symbols_data) = 0;
 
+  // Lay out sections--implemented by child class.
+  virtual void
+  do_layout(Layout*) = 0;
+
   // Get the file.
   Input_file*
   input_file() const
@@ -104,6 +146,16 @@ class Object
   const unsigned char*
   get_view(off_t start, off_t size);
 
+  // Get the number of sections.
+  unsigned int
+  shnum(void) const
+  { return this->shnum_; }
+
+  // Set the number of sections.
+  void
+  set_shnum(int shnum)
+  { this->shnum_ = shnum; }
+
   // Set the target.
   void
   set_target(Target* target)
@@ -117,6 +169,11 @@ class Object
   File_view*
   get_lasting_view(off_t start, off_t size);
 
+  // Return the vector mapping input sections to output sections.
+  std::vector<Map_to_output>&
+  map_to_output()
+  { return this->map_to_output_; }
+
  private:
   // This class may not be copied.
   Object(const Object&);
@@ -129,10 +186,14 @@ class Object
   // Offset within the file--0 for an object file, non-0 for an
   // archive.
   off_t offset_;
+  // Number of input sections.
+  unsigned int shnum_;
   // Whether this is a dynamic object.
   bool is_dynamic_;
   // Target functions--may be NULL if the target is not known.
   Target* target_;
+  // Mapping from input sections to output section.
+  std::vector<Map_to_output> map_to_output_;
 };
 
 // Implement sized_target inline for efficiency.  This approach breaks
@@ -158,15 +219,23 @@ class Sized_object : public Object
 
   ~Sized_object();
 
+  // Set up the object file based on the ELF header.
   void
   setup(const typename elfcpp::Ehdr<size, big_endian>&);
 
+  // Read the symbols.
   Read_symbols_data
   do_read_symbols();
 
+  // Add the symbols to the symbol table.
   void
   do_add_symbols(Symbol_table*, Read_symbols_data);
 
+  // Lay out the input sections.
+  void
+  do_layout(Layout*);
+
+  // Return the appropriate Sized_target structure.
   Sized_target<size, big_endian>*
   sized_target()
   { return this->Object::sized_target<size, big_endian>(); }
@@ -176,18 +245,27 @@ class Sized_object : public Object
   Sized_object(const Sized_object&);
   Sized_object& operator=(const Sized_object&);
 
-  // ELF file header EI_OSABI field.
-  unsigned char osabi_;
-  // ELF file header EI_ABIVERSION field.
-  unsigned char abiversion_;
-  // ELF file header e_machine field.
-  elfcpp::Elf_Half machine_;
+  // For convenience.
+  typedef Sized_object<size, big_endian> This;
+  static const int ehdr_size = elfcpp::Elf_sizes<size>::ehdr_size;
+  static const int shdr_size = elfcpp::Elf_sizes<size>::shdr_size;
+  static const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+
+  // Whether to include a section group in the link.
+  bool
+  include_section_group(Layout*, unsigned int,
+                       const elfcpp::Shdr<size, big_endian>&,
+                       std::vector<bool>*);
+
+  // Whether to include a linkonce section in the link.
+  bool
+  include_linkonce_section(Layout*, const char*,
+                          const elfcpp::Shdr<size, big_endian>&);
+
   // ELF file header e_flags field.
   unsigned int flags_;
   // File offset of section header table.
   off_t shoff_;
-  // Number of input sections.
-  unsigned int shnum_;
   // Offset of SHT_STRTAB section holding section names.
   unsigned int shstrndx_;
   // Index of SHT_SYMTAB section.
@@ -196,6 +274,10 @@ class Sized_object : public Object
   Symbol** symbols_;
 };
 
+// The type of the list of input objects.
+
+typedef std::list<Object*> Object_list;
+
 // Return an Object appropriate for the input file.  P is BYTES long,
 // and holds the ELF header.
 
index 082927f..6ac1ab9 100644 (file)
@@ -14,8 +14,6 @@
 
 #include <list>
 
-#include "gold.h"
-
 namespace gold
 {
 
diff --git a/gold/output.cc b/gold/output.cc
new file mode 100644 (file)
index 0000000..fcba113
--- /dev/null
@@ -0,0 +1,159 @@
+// output.cc -- manage the output file for gold
+
+#include "gold.h"
+
+#include <cstdlib>
+
+#include "object.h"
+#include "output.h"
+
+namespace gold
+{
+
+// Output_data methods.
+
+Output_data::~Output_data()
+{
+}
+
+// Output_data_const methods.
+
+void
+Output_data_const::write(Output_file* output, off_t off)
+{
+  output->write(off, data_.data(), data_.size());
+}
+
+// Output_section methods.
+
+// Construct an Output_section.  NAME will point into a Stringpool.
+
+Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
+                              elfcpp::Elf_Xword flags)
+  : name_(name),
+    addr_(0),
+    addralign_(0),
+    entsize_(0),
+    offset_(0),
+    size_(0),
+    link_(0),
+    info_(0),
+    type_(type),
+    flags_(flags)
+{
+}
+
+// Add an input section to an Output_section.  We don't keep track of
+// input sections for an Output_section.  Instead, each Object keeps
+// track of the Output_section for each of its input sections.
+
+template<int size, bool big_endian>
+off_t
+Output_section::add_input_section(Object* object, const char* secname,
+                                 const elfcpp::Shdr<size, big_endian>& shdr)
+{
+  elfcpp::Elf_Xword addralign = shdr.get_sh_addralign();
+  if ((addralign & (addralign - 1)) != 0)
+    {
+      fprintf(stderr, _("%s: %s: invalid alignment %lu for section \"%s\"\n"),
+             program_name, object->name().c_str(),
+             static_cast<unsigned long>(addralign), secname);
+      gold_exit(false);
+    }
+  this->size_ = (this->size_ + addralign - 1) &~ (addralign - 1);
+
+  if (addralign > this->addralign_)
+    this->addralign_ = addralign;
+
+  off_t ret = this->size_;
+  this->size_ += shdr.get_sh_size();
+
+  return ret;
+}
+
+// Output segment methods.
+
+Output_segment::Output_segment(elfcpp::Elf_Word type, elfcpp::Elf_Word flags)
+  : output_sections_(),
+    vaddr_(0),
+    paddr_(0),
+    memsz_(0),
+    align_(0),
+    offset_(0),
+    filesz_(0),
+    type_(type),
+    flags_(flags)
+{
+}
+
+// Add an Output_section to an Output_segment.
+
+void
+Output_segment::add_output_section(Output_section* os)
+{
+  // So that PT_NOTE segments will work correctly, we need to ensure
+  // that all SHT_NOTE sections are adjacent.  This will normally
+  // happen automatically, because all the SHT_NOTE input sections
+  // will wind up in the same output section.  However, it is possible
+  // for multiple SHT_NOTE input sections to have different section
+  // flags, and thus be in different output sections, but for the
+  // different section flags to map into the same segment flags and
+  // thus the same output segment.
+  if (os->type() == elfcpp::SHT_NOTE)
+    {
+      for (Section_list::iterator p = this->output_sections_.begin();
+          p != this->output_sections_.end();
+          ++p)
+       {
+         if ((*p)->type() == elfcpp::SHT_NOTE)
+           {
+             ++p;
+             this->output_sections_.insert(p, os);
+             return;
+           }
+       }
+    }
+
+  this->output_sections_.push_back(os);
+}
+
+// Output_file methods.
+
+void
+Output_file::write(off_t, const void*, off_t)
+{
+  abort();
+}
+
+// Instantiate the templates we need.  We could use the configure
+// script to restrict this to only the ones for implemented targets.
+
+template
+off_t
+Output_section::add_input_section<32, false>(
+    Object* object,
+    const char* secname,
+    const elfcpp::Shdr<32, false>& shdr);
+
+template
+off_t
+Output_section::add_input_section<32, true>(
+    Object* object,
+    const char* secname,
+    const elfcpp::Shdr<32, true>& shdr);
+
+template
+off_t
+Output_section::add_input_section<64, false>(
+    Object* object,
+    const char* secname,
+    const elfcpp::Shdr<64, false>& shdr);
+
+template
+off_t
+Output_section::add_input_section<64, true>(
+    Object* object,
+    const char* secname,
+    const elfcpp::Shdr<64, true>& shdr);
+
+} // End namespace gold.
diff --git a/gold/output.h b/gold/output.h
new file mode 100644 (file)
index 0000000..943474b
--- /dev/null
@@ -0,0 +1,214 @@
+// output.h -- manage the output file for gold   -*- C++ -*-
+
+#ifndef GOLD_OUTPUT_H
+#define GOLD_OUTPUT_H
+
+#include <list>
+
+#include "elfcpp.h"
+
+namespace gold
+{
+
+class Object;
+class Output_file;
+
+// An abtract class for data which has to go into the output file
+// which is not associated with any input section.
+
+class Output_data
+{
+ public:
+  Output_data(off_t size = 0)
+    : size_(size)
+  { }
+
+  virtual
+  ~Output_data();
+
+  // Return the size of the data.
+  off_t
+  size()
+  { return this->size_; }
+
+  // Write the data to the output file at the specified offset.  This
+  // must be implemented by the real class.
+  virtual void
+  write(Output_file*, off_t off) = 0;
+
+ protected:
+  // Set the size of the data.
+  void
+  set_size(off_t size)
+  { this->size_ = size; }
+
+ private:
+  Output_data(const Output_data&);
+  Output_data& operator=(const Output_data&);
+
+  // Size of data in file.
+  off_t size_;
+};
+
+// A simple cass of Output_data in which we have constant data to
+// output.
+
+class Output_data_const : public Output_data
+{
+ public:
+  Output_data_const(const std::string& data)
+    : Output_data(data.size()), data_(data)
+  { }
+
+  Output_data_const(const char* p, off_t len)
+    : Output_data(len), data_(p, len)
+  { }
+
+  void
+  write(Output_file* output, off_t off);
+
+ private:
+  std::string data_;
+};
+
+// An output section.  We don't expect to have too many output
+// sections, so we don't bother to do a template on the size.
+
+class Output_section
+{
+ public:
+  // Create an output section, giving the name, type, and flags.
+  Output_section(const char* name, elfcpp::Elf_Word, elfcpp::Elf_Xword);
+  ~Output_section();
+
+  // Add a new input section named NAME with header SHDR from object
+  // OBJECT.  Return the offset within the output section.
+  template<int size, bool big_endian>
+  off_t
+  add_input_section(Object* object, const char *name,
+                   const elfcpp::Shdr<size, big_endian>& shdr);
+
+  // Return the section name.
+  const char*
+  name() const
+  { return this->name_; }
+
+  // Return the section type.
+  elfcpp::Elf_Word
+  type() const
+  { return this->type_; }
+
+  // Return the section flags.
+  elfcpp::Elf_Xword
+  flags() const
+  { return this->flags_; }
+
+ private:
+  // Most of these fields are only valid after layout.
+
+  // The name of the section.  This will point into a Stringpool.
+  const char* name_;
+  // The section address.
+  uint64_t addr_;
+  // The section alignment.
+  uint64_t addralign_;
+  // The section entry size.
+  uint64_t entsize_;
+  // The file offset.
+  off_t offset_;
+  // The section size.
+  off_t size_;
+  // The section link field.
+  unsigned int link_;
+  // The section info field.
+  unsigned int info_;
+  // The section type.
+  elfcpp::Elf_Word type_;
+  // The section flags.
+  elfcpp::Elf_Xword flags_;
+};
+
+// An output segment.  PT_LOAD segments are built from collections of
+// output sections.  Other segments typically point within PT_LOAD
+// segments, and are built directly as needed.
+
+class Output_segment
+{
+ public:
+  // Create an output segment, specifying the type and flags.
+  Output_segment(elfcpp::Elf_Word, elfcpp::Elf_Word);
+
+  // Return the virtual address.
+  uint64_t
+  vaddr() const
+  { return this->vaddr_; }
+
+  // Return the physical address.
+  uint64_t
+  paddr() const
+  { return this->paddr_; }
+
+  // Return the segment type.
+  elfcpp::Elf_Word
+  type() const
+  { return this->type_; }
+
+  // Return the segment flags.
+  elfcpp::Elf_Word
+  flags() const
+  { return this->flags_; }
+
+  // Add an Output_section to this segment.
+  void
+  add_output_section(Output_section*);
+
+  // Update the segment flags to be compatible with FLAGS.
+  void
+  update_flags(elfcpp::Elf_Word flags)
+  { this->flags_ |= flags & (elfcpp::PF_R | elfcpp::PF_W | elfcpp::PF_X); }
+
+ private:
+  Output_segment(const Output_segment&);
+  Output_segment& operator=(const Output_segment&);
+
+  typedef std::list<Output_section*> Section_list;
+
+  // The list of output sections attached to this segment.  This is
+  // cleared after layout.
+  Section_list output_sections_;
+  // The segment virtual address.
+  uint64_t vaddr_;
+  // The segment physical address.
+  uint64_t paddr_;
+  // The size of the segment in memory.
+  uint64_t memsz_;
+  // The segment alignment.
+  uint64_t align_;
+  // The offset of the segment data within the file.
+  off_t offset_;
+  // The size of the segment data in the file.
+  off_t filesz_;
+  // The segment type;
+  elfcpp::Elf_Word type_;
+  // The segment flags.
+  elfcpp::Elf_Word flags_;
+};
+
+// This class represents the output file.  The output file is a
+// collection of output segments and a collection of output sections
+// which are not associated with segments.
+
+class Output_file
+{
+ public:
+  Output_file();
+  ~Output_file();
+
+  // Write data to the output file.
+  void
+  write(off_t off, const void* data, off_t len);
+};
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_OUTPUT_H)
index 35c5094..4bb4aad 100644 (file)
@@ -7,10 +7,14 @@ gold.h
 gold-threads.cc
 gold-threads.h
 i386.cc
+layout.cc
+layout.h
 object.cc
 object.h
 options.cc
 options.h
+output.cc
+output.h
 readsyms.cc
 readsyms.h
 resolve.cc
@@ -21,6 +25,5 @@ symtab.h
 target.h
 target-select.cc
 target-select.h
-targetsize.h
 workqueue.cc
 workqueue.h
index 5d13088..e12e01e 100644 (file)
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2006-09-07 14:17-0700\n"
+"POT-Creation-Date: 2006-09-21 13:30-0700\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -51,7 +51,7 @@ msgstr ""
 msgid "%s: cannot open %s: %s"
 msgstr ""
 
-#: gold.cc:72
+#: gold.cc:74
 msgid "no input files"
 msgstr ""
 
@@ -99,73 +99,103 @@ msgstr ""
 msgid "pthread_cond_signal failed"
 msgstr ""
 
-#: object.cc:57
+#: object.cc:54
 #, c-format
 msgid "%s: %s: bad e_ehsize field (%d != %d)\n"
 msgstr ""
 
-#: object.cc:64
+#: object.cc:61
 #, c-format
 msgid "%s: %s: bad e_shentsize field (%d != %d)\n"
 msgstr ""
 
-#: object.cc:88
+#: object.cc:87
 #, c-format
 msgid "%s: %s: unsupported ELF machine number %d\n"
 msgstr ""
 
-#: object.cc:167
+#: object.cc:165
 #, c-format
 msgid "%s: %s: invalid symbol table name index: %u\n"
 msgstr ""
 
-#: object.cc:177
+#: object.cc:175
 #, c-format
 msgid "%s: %s: symbol table name section has wrong type: %u\n"
 msgstr ""
 
-#: object.cc:214
+#: object.cc:212
 #, c-format
 msgid "%s: %s: size of symbols is not multiple of symbol size\n"
 msgstr ""
 
+#: object.cc:266
+#, c-format
+msgid "%s: %s: section group %u link %u out of range\n"
+msgstr ""
+
+#: object.cc:277
+#, c-format
+msgid "%s: %s: section group %u info %u out of range\n"
+msgstr ""
+
+#: object.cc:288
+#, c-format
+msgid "%s; %s: symtab section %u link %u out of range\n"
+msgstr ""
+
+#: object.cc:306
+#, c-format
+msgid "%s: %s: symbol %u name offset %u out of range\n"
+msgstr ""
+
+#: object.cc:328
+#, c-format
+msgid "%s: %s: section %u in section group %u out of range"
+msgstr ""
+
+#: object.cc:407
+#, c-format
+msgid "%s: %s: bad section name offset for section %u: %lu\n"
+msgstr ""
+
 #. elfcpp::ET_DYN
-#: object.cc:262
+#: object.cc:480
 #, c-format
 msgid "%s: %s: dynamic objects are not yet supported\n"
 msgstr ""
 
-#: object.cc:286 object.cc:339 object.cc:360
+#: object.cc:504 object.cc:557 object.cc:578
 #, c-format
 msgid "%s: %s: ELF file too short\n"
 msgstr ""
 
-#: object.cc:295
+#: object.cc:513
 #, c-format
 msgid "%s: %s: invalid ELF version 0\n"
 msgstr ""
 
-#: object.cc:298
+#: object.cc:516
 #, c-format
 msgid "%s: %s: unsupported ELF version %d\n"
 msgstr ""
 
-#: object.cc:306
+#: object.cc:524
 #, c-format
 msgid "%s: %s: invalid ELF class 0\n"
 msgstr ""
 
-#: object.cc:313
+#: object.cc:531
 #, c-format
 msgid "%s: %s: unsupported ELF class %d\n"
 msgstr ""
 
-#: object.cc:321
+#: object.cc:539
 #, c-format
 msgid "%s: %s: invalid ELF data encoding\n"
 msgstr ""
 
-#: object.cc:328
+#: object.cc:546
 #, c-format
 msgid "%s: %s: unsupported ELF data encoding %d\n"
 msgstr ""
@@ -220,6 +250,11 @@ msgstr ""
 msgid "%s: -%c: %s\n"
 msgstr ""
 
+#: output.cc:58
+#, c-format
+msgid "%s: %s: invalid alignment %lu for section \"%s\"\n"
+msgstr ""
+
 #: resolve.cc:135
 #, c-format
 msgid "%s: %s: invalid STB_LOCAL symbol %s in external symbols\n"
index 1076e6c..aa32e36 100644 (file)
@@ -8,6 +8,7 @@
 #include "options.h"
 #include "dirsearch.h"
 #include "readsyms.h"
+#include "object.h"
 
 namespace gold
 {
@@ -49,8 +50,6 @@ Read_symbols::locks(Workqueue*)
 void
 Read_symbols::run(Workqueue* workqueue)
 {
-  // We don't keep track of Input_file objects, so this is a memory
-  // leak.
   Input_file* input_file = new Input_file(this->input_);
   input_file->open(this->options_, this->dirpath_);
 
@@ -71,7 +70,9 @@ Read_symbols::run(Workqueue* workqueue)
          // This is an ELF object.
          Object* obj = make_elf_object(this->input_.name(), input_file, 0,
                                        p, bytes);
-                                       
+
+         this->input_objects_->push_back(obj);
+
          Read_symbols_data sd = obj->read_symbols();
          workqueue->queue(new Add_symbols(this->symtab_, obj, sd,
                                           this->this_blocker_,
@@ -99,20 +100,37 @@ Add_symbols::~Add_symbols()
   // input file.
 }
 
-// We are blocked by this_blocker_.  We block next_blocker_.
+// We are blocked by this_blocker_.  We block next_blocker_.  We also
+// lock the file.
 
 Task::Is_runnable_type
 Add_symbols::is_runnable(Workqueue*)
 {
   if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked())
     return IS_BLOCKED;
+  if (this->object_->is_locked())
+    return IS_LOCKED;
   return IS_RUNNABLE;
 }
 
+class Add_symbols::Add_symbols_locker : public Task_locker
+{
+ public:
+  Add_symbols_locker(Task_token& token, Workqueue* workqueue,
+                    Object* object)
+    : blocker_(token, workqueue), objlock_(*object)
+  { }
+
+ private:
+  Task_locker_block blocker_;
+  Task_locker_obj<Object> objlock_;
+};
+
 Task_locker*
 Add_symbols::locks(Workqueue* workqueue)
 {
-  return new Task_locker_block(*this->next_blocker_, workqueue);
+  return new Add_symbols_locker(*this->next_blocker_, workqueue,
+                               this->object_);
 }
 
 void
index f01cf61..73d4efe 100644 (file)
@@ -3,7 +3,6 @@
 #ifndef GOLD_READSYMS_H
 #define GOLD_READSYMS_H
 
-#include "targetsize.h"
 #include "workqueue.h"
 #include "object.h"
 
@@ -26,11 +25,13 @@ class Read_symbols : public Task
   // associated Add_symbols task from running before the previous one
   // has completed; it will be NULL for the first task.  NEXT_BLOCKER
   // is used to block the next input file from adding symbols.
-  Read_symbols(const General_options& options, Symbol_table* symtab,
-              const Dirsearch& dirpath, const Input_argument& input,
+  Read_symbols(const General_options& options, Object_list* input_objects,
+              Symbol_table* symtab, const Dirsearch& dirpath,
+              const Input_argument& input,
               Task_token* this_blocker, Task_token* next_blocker)
-    : options_(options), symtab_(symtab), dirpath_(dirpath), input_(input),
-      this_blocker_(this_blocker), next_blocker_(next_blocker)
+    : options_(options), input_objects_(input_objects), symtab_(symtab),
+      dirpath_(dirpath), input_(input), this_blocker_(this_blocker),
+      next_blocker_(next_blocker)
   { }
 
   ~Read_symbols();
@@ -48,6 +49,7 @@ class Read_symbols : public Task
 
  private:
   const General_options& options_;
+  Object_list* input_objects_;
   Symbol_table* symtab_;
   const Dirsearch& dirpath_;
   const Input_argument& input_;
@@ -85,6 +87,8 @@ class Add_symbols : public Task
   run(Workqueue*);
 
 private:
+  class Add_symbols_locker;
+
   Symbol_table* symtab_;
   Object* object_;
   Read_symbols_data sd_;
index 0368014..9a709e0 100644 (file)
@@ -101,7 +101,7 @@ Stringpool::add(const char* s)
 {
   // FIXME: This will look up the entry twice in the hash table.  The
   // problem is that we can't insert S before we canonicalize it.  I
-  // don't think there is a way to handle this correct with
+  // don't think there is a way to handle this correctly with
   // unordered_set, so this should be replaced with custom code to do
   // what we need, which is to return the empty slot.
 
index a90ba5d..a7d3423 100644 (file)
@@ -7,7 +7,6 @@
 #include <utility>
 
 #include "elfcpp.h"
-#include "targetsize.h"
 #include "stringpool.h"
 
 #ifndef GOLD_SYMTAB_H
diff --git a/gold/targetsize.h b/gold/targetsize.h
deleted file mode 100644 (file)
index 61f986d..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-// targetsize.h -- representations which change size based on the target
-
-#ifndef GOLD_TARGETSIZE_H
-#define GOLD_TARGETSIZE_H
-
-// Tell GNU/Linux inttypes.h that we want the formatting macros.
-#define __STDC_FORMAT_MACROS
-
-#include <stdint.h>
-#include <inttypes.h>
-
-namespace gold
-{
-
-// A template we use to get the right type sizes via specialization.
-// We never actually use the default version.
-
-template<int size>
-struct Size_types
-{
-  typedef signed char Signed_type;
-  typedef unsigned char Unsigned_type;
-  static const char* signed_printf_dec_format();
-  static const char* unsigned_printf_dec_format();
-  static const char* unsigned_printf_hex_format();
-};
-
-template<>
-struct Size_types<32>
-{
-  typedef int32_t Signed_type;
-  typedef uint32_t Unsigned_type;
-  static const char* signed_printf_dec_format()
-  { return PRId32; }
-  static const char* unsigned_printf_dec_format()
-  { return PRIu32; }
-  static const char* unsigned_printf_hex_format()
-  { return PRIx32; }
-};
-
-template<>
-struct Size_types<64>
-{
-  typedef int64_t Signed_type;
-  typedef uint64_t Unsigned_type;
-  static const char* signed_printf_dec_format()
-  { return PRId64; }
-  static const char* unsigned_printf_dec_format()
-  { return PRIu64; }
-  static const char* unsigned_printf_hex_format()
-  { return PRIx64; }
-};
-
-} // End namespace gold.
-
-#endif // !defined(GOLD_TARGETSIZE_H)
index 5949cf5..a97d86d 100644 (file)
@@ -146,6 +146,27 @@ class Task_block_token
   Workqueue* workqueue_;
 };
 
+// An object which implements an RAII lock for any object which
+// supports lock and unlock methods.
+
+template<typename Obj>
+class Task_lock_obj
+{
+ public:
+  Task_lock_obj(Obj& obj)
+    : obj_(obj)
+  { this->obj_.lock(); }
+
+  ~Task_lock_obj()
+  { this->obj_.unlock(); }
+
+ private:
+  Task_lock_obj(const Task_lock_obj&);
+  Task_lock_obj& operator=(const Task_lock_obj&);
+
+  Obj& obj_;
+};
+
 // An abstract class used to lock Task_tokens using RAII.  A typical
 // implementation would simply have a set of members of type
 // Task_read_token, Task_write_token, and Task_block_token.
@@ -209,21 +230,22 @@ class Task_locker_block : public Task_locker
   Task_block_token block_token_;
 };
 
-// A version of Task_locker which may be used to hold a lock on a
-// File_read.
+// A version of Task_locker which may be used to hold a lock on any
+// object which supports lock() and unlock() methods.
 
-class Task_locker_file : public Task_locker
+template<typename Obj>
+class Task_locker_obj : public Task_locker
 {
  public:
-  Task_locker_file(File_read& file)
-    : file_lock_(file)
+  Task_locker_obj(Obj& obj)
+    : obj_lock_(obj)
   { }
 
  private:
-  Task_locker_file(const Task_locker_file&);
-  Task_locker_file& operator=(const Task_locker_file&);
+  Task_locker_obj(const Task_locker_obj&);
+  Task_locker_obj& operator=(const Task_locker_obj&);
 
-  File_read_lock file_lock_;
+  Task_lock_obj<Obj> obj_lock_;
 };
 
 // The superclass for tasks to be placed on the workqueue.  Each