Finished layout code.
authorIan Lance Taylor <iant@google.com>
Wed, 27 Sep 2006 22:53:42 +0000 (22:53 +0000)
committerIan Lance Taylor <iant@google.com>
Wed, 27 Sep 2006 22:53:42 +0000 (22:53 +0000)
12 files changed:
gold/gold.cc
gold/i386.cc
gold/layout.cc
gold/layout.h
gold/object.cc
gold/object.h
gold/output.cc
gold/output.h
gold/po/gold.pot
gold/symtab.cc
gold/symtab.h
gold/target.h

index f4642cf..9576e4a 100644 (file)
@@ -91,7 +91,8 @@ queue_initial_tasks(const General_options& options,
       this_blocker = next_blocker;
     }
 
-  workqueue->queue(new Layout_task(options, input_objects, this_blocker));
+  workqueue->queue(new Layout_task(options, input_objects, symtab,
+                                  this_blocker));
 }
 
 } // end anonymous namespace.
index 5ecd2e3..21dd57a 100644 (file)
@@ -16,8 +16,22 @@ class Target_i386 : public Sized_target<32, false>
 {
  public:
   Target_i386()
-    : Sized_target<32, false>(false, false)
+    : Sized_target<32, false>(&i386_info)
   { }
+
+ private:
+  static const Target::Target_info i386_info;
+};
+
+const Target::Target_info Target_i386::i386_info =
+{
+  32,          // size
+  false,       // is_big_endian
+  false,       // has_make_symbol
+  false,       // has_resolve,
+  0x08048000,  // text_segment_address,
+  0x1000,      // abi_pagesize
+  0x1000       // common_pagesize
 };
 
 // The selector for i386 object files.
index 1584380..d91f731 100644 (file)
@@ -52,15 +52,14 @@ Layout_task::run(Workqueue*)
        p != this->input_objects_->end();
        ++p)
     (*p)->layout(&layout);
-  layout.finalize(this->input_objects_);
+  layout.finalize(this->input_objects_, this->symtab_);
 }
 
 // Layout methods.
 
 Layout::Layout(const General_options& options)
-  : options_(options), namepool_(), signatures_(),
-    section_name_map_(), segment_list_(), section_list_(),
-    data_list_()
+  : options_(options), namepool_(), sympool_(), signatures_(),
+    section_name_map_(), segment_list_(), section_list_()
 {
 }
 
@@ -169,82 +168,6 @@ Layout::layout(Object* object, const char* name,
   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
@@ -289,7 +212,7 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
          if ((*p)->type() == elfcpp::PT_LOAD
              && ((*p)->flags() & elfcpp::PF_W) == (seg_flags & elfcpp::PF_W))
            {
-             (*p)->add_output_section(os);
+             (*p)->add_output_section(os, seg_flags);
              break;
            }
        }
@@ -299,7 +222,7 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
          Output_segment* oseg = new Output_segment(elfcpp::PT_LOAD,
                                                    seg_flags);
          this->segment_list_.push_back(oseg);
-         oseg->add_output_section(os);
+         oseg->add_output_section(os, seg_flags);
        }
 
       // If we see a loadable SHT_NOTE section, we create a PT_NOTE
@@ -315,7 +238,7 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
                  && (((*p)->flags() & elfcpp::PF_W)
                      == (seg_flags & elfcpp::PF_W)))
                {
-                 (*p)->add_output_section(os);
+                 (*p)->add_output_section(os, seg_flags);
                  break;
                }
            }
@@ -325,7 +248,7 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
              Output_segment* oseg = new Output_segment(elfcpp::PT_NOTE,
                                                        seg_flags);
              this->segment_list_.push_back(oseg);
-             oseg->add_output_section(os);
+             oseg->add_output_section(os, seg_flags);
            }
        }
 
@@ -342,7 +265,7 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
                  && (((*p)->flags() & elfcpp::PF_W)
                      == (seg_flags & elfcpp::PF_W)))
                {
-                 (*p)->add_output_section(os);
+                 (*p)->add_output_section(os, seg_flags);
                  break;
                }
            }
@@ -352,7 +275,7 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
              Output_segment* oseg = new Output_segment(elfcpp::PT_TLS,
                                                        seg_flags);
              this->segment_list_.push_back(oseg);
-             oseg->add_output_section(os);
+             oseg->add_output_section(os, seg_flags);
            }
        }
     }
@@ -360,11 +283,25 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
   return os;
 }
 
-// Create the sections for the symbol table.
+// Find the first read-only PT_LOAD segment, creating one if
+// necessary.
 
-void
-Layout::create_symtab_sections()
+Output_segment*
+Layout::find_first_load_seg()
 {
+  for (Segment_list::const_iterator p = this->segment_list_.begin();
+       p != this->segment_list_.end();
+       ++p)
+    {
+      if ((*p)->type() == elfcpp::PT_LOAD
+         && ((*p)->flags() & elfcpp::PF_R) != 0
+         && ((*p)->flags() & elfcpp::PF_W) == 0)
+       return *p;
+    }
+
+  Output_segment* load_seg = new Output_segment(elfcpp::PT_LOAD, elfcpp::PF_R);
+  this->segment_list_.push_back(load_seg);
+  return load_seg;
 }
 
 // Finalize the layout.  When this is called, we have created all the
@@ -383,13 +320,13 @@ Layout::create_symtab_sections()
 // 4) Determine the final file offset of all the SHF_ALLOC output
 // sections.
 
-// 5) Finalize the symbol table: set symbol values to their final
+// 5) Create the symbol table sections and the section name table
+// section.
+
+// 6) Finalize the symbol table: set symbol values to their final
 // value and make a final determination of which symbols are going
 // into the output symbol table.
 
-// 6) Create the symbol table sections and the section name table
-// section.
-
 // 7) Create the section table header.
 
 // 8) Determine the final file offset of all the output sections which
@@ -397,8 +334,10 @@ Layout::create_symtab_sections()
 
 // 9) Finalize the ELF file header.
 
-void
-Layout::finalize(const Input_objects* input_objects)
+// This function returns the size of the output file.
+
+off_t
+Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
 {
   if (input_objects->any_dynamic())
     {
@@ -411,11 +350,298 @@ Layout::finalize(const Input_objects* input_objects)
 
   // FIXME: Handle PT_GNU_STACK.
 
+  Output_segment* load_seg = this->find_first_load_seg();
+
+  // Lay out the segment headers.
+  int size = input_objects->target()->get_size();
+  Output_segment_headers* segment_headers;
+  segment_headers = new Output_segment_headers(size, this->segment_list_);
+  load_seg->add_initial_output_data(segment_headers);
+  // FIXME: Attach them to PT_PHDRS if necessary.
+
+  // Lay out the file header.
+  Output_file_header* file_header;
+  file_header = new Output_file_header(size,
+                                      this->options_,
+                                      input_objects->target(),
+                                      symtab,
+                                      segment_headers);
+  load_seg->add_initial_output_data(file_header);
+
+  // Set the file offsets of all the segments.
+  off_t off = this->set_segment_offsets(input_objects->target(), load_seg);
+
+  // Create the symbol table sections.
+  // FIXME: We don't need to do this if we are stripping symbols.
+  Output_section* osymtab;
+  Output_section* ostrtab;
+  this->create_symtab_sections(input_objects, symtab, &osymtab, &ostrtab);
+
+  // Create the .shstrtab section.
+  Output_section* shstrtab_section = this->create_shstrtab();
+
+  // Set the file offsets of all the sections not associated with
+  // segments.
+  off = this->set_section_offsets(off);
+
+  // Create the section table header.
+  Output_section_headers* oshdrs = this->create_shdrs(size, off);
+  off += oshdrs->data_size();
+
+  file_header->set_section_info(oshdrs, shstrtab_section);
+
+  // Now we know exactly where everything goes in the output file.
+
+  return off;
+}
+
+// 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;
+}
+
+// Set the file offsets of all the segments.  They have all been
+// created.  LOAD_SEG must be be laid out first.  Return the offset of
+// the data to follow.
+
+off_t
+Layout::set_segment_offsets(const Target* target, Output_segment* load_seg)
+{
+  // Sort them into the final order.
   std::sort(this->segment_list_.begin(), this->segment_list_.end(),
            Layout::Compare_segments());
 
-  Output_segment_headers* segment_headers;
-  segment_headers = new Output_segment_headers(this->segment_list_);
+  // Find the PT_LOAD segments, and set their addresses and offsets
+  // and their section's addresses and offsets.
+  uint64_t addr = target->text_segment_address();
+  off_t off = 0;
+  bool was_readonly = false;
+  for (Segment_list::iterator p = this->segment_list_.begin();
+       p != this->segment_list_.end();
+       ++p)
+    {
+      if ((*p)->type() == elfcpp::PT_LOAD)
+       {
+         if (load_seg != NULL && load_seg != *p)
+           abort();
+         load_seg = NULL;
+
+         // If the last segment was readonly, and this one is not,
+         // then skip the address forward one page, maintaining the
+         // same position within the page.  This lets us store both
+         // segments overlapping on a single page in the file, but
+         // the loader will put them on different pages in memory.
+
+         uint64_t orig_addr = addr;
+         uint64_t orig_off = off;
+
+         uint64_t aligned_addr = addr;
+         uint64_t abi_pagesize = target->abi_pagesize();
+         if (was_readonly && ((*p)->flags() & elfcpp::PF_W) != 0)
+           {
+             uint64_t align = (*p)->max_data_align();
+
+             addr = (addr + align - 1) & ~ (align - 1);
+             aligned_addr = addr;
+             if ((addr & (abi_pagesize - 1)) != 0)
+               addr = addr + abi_pagesize;
+           }
+
+         off = orig_off + ((addr - orig_addr) & (abi_pagesize - 1));
+         uint64_t new_addr = (*p)->set_section_addresses(addr, &off);
+
+         // Now that we know the size of this segment, we may be able
+         // to save a page in memory, at the cost of wasting some
+         // file space, by instead aligning to the start of a new
+         // page.  Here we use the real machine page size rather than
+         // the ABI mandated page size.
+
+         if (aligned_addr != addr)
+           {
+             uint64_t common_pagesize = target->common_pagesize();
+             uint64_t first_off = (common_pagesize
+                                   - (aligned_addr
+                                      & (common_pagesize - 1)));
+             uint64_t last_off = new_addr & (common_pagesize - 1);
+             if (first_off > 0
+                 && last_off > 0
+                 && ((aligned_addr & ~ (common_pagesize - 1))
+                     != (new_addr & ~ (common_pagesize - 1)))
+                 && first_off + last_off <= common_pagesize)
+               {
+                 addr = ((aligned_addr + common_pagesize - 1)
+                         & ~ (common_pagesize - 1));
+                 off = orig_off + ((addr - orig_addr) & (abi_pagesize - 1));
+                 new_addr = (*p)->set_section_addresses(addr, &off);
+               }
+           }
+
+         addr = new_addr;
+
+         if (((*p)->flags() & elfcpp::PF_W) == 0)
+           was_readonly = true;
+       }
+    }
+
+  // Handle the non-PT_LOAD segments, setting their offsets from their
+  // section's offsets.
+  for (Segment_list::iterator p = this->segment_list_.begin();
+       p != this->segment_list_.end();
+       ++p)
+    {
+      if ((*p)->type() != elfcpp::PT_LOAD)
+       (*p)->set_offset();
+    }
+
+  return off;
+}
+
+// Set the file offset of all the sections not associated with a
+// segment.
+
+off_t
+Layout::set_section_offsets(off_t off)
+{
+  for (Layout::Section_list::iterator p = this->section_list_.begin();
+       p != this->section_list_.end();
+       ++p)
+    {
+      uint64_t addralign = (*p)->addralign();
+      off = (off + addralign - 1) & ~ (addralign - 1);
+      (*p)->set_address(0, off);
+      off += (*p)->data_size();
+    }
+  return off;
+}
+
+// Create the symbol table sections.
+
+void
+Layout::create_symtab_sections(const Input_objects* input_objects,
+                              Symbol_table* symtab,
+                              Output_section** posymtab,
+                              Output_section** postrtab)
+{
+  off_t off = 0;
+  for (Input_objects::Object_list::const_iterator p = input_objects->begin();
+       p != input_objects->end();
+       ++p)
+    {
+      Task_lock_obj<Object> tlo(**p);
+      off = (*p)->finalize_local_symbols(off, &this->sympool_);
+    }
+
+  off = symtab->finalize(off, &this->sympool_);
+
+  *posymtab = new Output_section_symtab(this->namepool_.add(".symtab"), off);
+  *postrtab = new Output_section_strtab(this->namepool_.add(".strtab"),
+                                       &this->sympool_);
+}
+
+// Create the .shstrtab section, which holds the names of the
+// sections.  At the time this is called, we have created all the
+// output sections except .shstrtab itself.
+
+Output_section*
+Layout::create_shstrtab()
+{
+  // FIXME: We don't need to create a .shstrtab section if we are
+  // stripping everything.
+
+  const char* name = this->namepool_.add(".shstrtab");
+
+  Output_section* os = new Output_section_strtab(name,
+                                                &this->namepool_);
+
+  this->section_list_.push_back(os);
+
+  return os;
+}
+
+// Create the section headers.  SIZE is 32 or 64.  OFF is the file
+// offset.
+
+Output_section_headers*
+Layout::create_shdrs(int size, off_t off)
+{
+  Output_section_headers* oshdrs;
+  oshdrs = new Output_section_headers(size, this->segment_list_,
+                                     this->section_list_);
+  uint64_t addralign = oshdrs->addralign();
+  off = (off + addralign - 1) & ~ (addralign - 1);
+  oshdrs->set_address(0, off);
+  return oshdrs;
 }
 
 // The mapping of .gnu.linkonce section names to real section names.
index 89ad8c4..75b2151 100644 (file)
@@ -17,8 +17,10 @@ namespace gold
 {
 
 class Input_objects;
+class Symbol_table;
 class Output_section;
 class Output_section_symtab;
+class Output_section_headers;
 class Output_segment;
 class Output_data;
 
@@ -33,8 +35,9 @@ class Layout_task : public Task
   // from executing until all the input symbols have been read.
   Layout_task(const General_options& options,
              const Input_objects* input_objects,
+             Symbol_table* symtab,
              Task_token* this_blocker)
-    : options_(options), input_objects_(input_objects),
+    : options_(options), input_objects_(input_objects), symtab_(symtab),
       this_blocker_(this_blocker)
   { }
 
@@ -57,6 +60,7 @@ class Layout_task : public Task
 
   const General_options& options_;
   const Input_objects* input_objects_;
+  Symbol_table* symtab_;
   Task_token* this_blocker_;
 };
 
@@ -94,8 +98,8 @@ class Layout
   add_comdat(const char*, bool group);
 
   // Finalize the layout after all the input sections have been added.
-  void
-  finalize(const Input_objects*);
+  off_t
+  finalize(const Input_objects*, Symbol_table*);
 
   // The list of segments.
 
@@ -123,18 +127,33 @@ class Layout
   static const Linkonce_mapping linkonce_mapping[];
   static const int linkonce_mapping_count;
 
-  // Lay out the local symbols from a SHT_SYMTAB section.
-  template<int size, bool big_endian>
-  void
-  add_symtab_locals(Object* object, const elfcpp::Shdr<size, big_endian>&);
+  // Find the first read-only PT_LOAD segment, creating one if
+  // necessary.
+  Output_segment*
+  find_first_load_seg();
+
+  // Set the final file offsets of all the segments.
+  off_t
+  set_segment_offsets(const Target*, Output_segment*);
+
+  // Set the final file offsets of all the sections not associated
+  // with a segment.
+  off_t
+  set_section_offsets(off_t);
 
   // Create the output sections for the symbol table.
   void
-  create_symtab_sections();
+  create_symtab_sections(const Input_objects*, Symbol_table*,
+                        Output_section** osymtab,
+                        Output_section** ostrtab);
 
-  // Finalize the symbol table.
-  void
-  finalize_symtab();
+  // Create the .shstrtab section.
+  Output_section*
+  create_shstrtab();
+
+  // Create the section header table.
+  Output_section_headers*
+  create_shdrs(int size, off_t);
 
   // Return whether to include this section in the link.
   template<int size, bool big_endian>
@@ -190,6 +209,8 @@ class Layout
   const General_options& options_;
   // The output section names.
   Stringpool namepool_;
+  // The output symbol names.
+  Stringpool sympool_;
   // 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.
@@ -199,9 +220,6 @@ class Layout
   // The list of output sections which are not attached to any output
   // segment.
   Section_list section_list_;
-  // The list of output data objects which are not attached to any
-  // output section or output segment.
-  Data_list data_list_;
 };
 
 } // End namespace gold.
index 04a31bd..85019fb 100644 (file)
@@ -47,7 +47,8 @@ Sized_object<size, big_endian>::Sized_object(
     shoff_(ehdr.get_e_shoff()),
     shstrndx_(0),
     symtab_shnum_(0),
-    symbols_(NULL)
+    symbols_(NULL),
+    local_symbol_offset_(0)
 {
   if (ehdr.get_e_ehsize() != This::ehdr_size)
     {
@@ -70,6 +71,16 @@ Sized_object<size, big_endian>::~Sized_object()
 {
 }
 
+// Read the section header for section SHNUM.
+
+template<int size, bool big_endian>
+const unsigned char*
+Sized_object<size, big_endian>::section_header(unsigned int shnum)
+{
+  off_t symtabshdroff = this->shoff_ + shnum * This::shdr_size;
+  return this->get_view(symtabshdroff, This::shdr_size);
+}
+
 // Set up an object file bsaed on the file header.  This sets up the
 // target and reads the section information.
 
@@ -94,8 +105,7 @@ 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_, This::shdr_size);
-      elfcpp::Shdr<size, big_endian> shdr(p);
+      typename This::Shdr shdr(this->section_header(0));
       if (shnum == 0)
        shnum = shdr.get_sh_size();
       if (shstrndx == elfcpp::SHN_XINDEX)
@@ -114,7 +124,7 @@ Sized_object<size, big_endian>::setup(
   p += This::shdr_size;
   for (unsigned int i = 1; i < shnum; ++i)
     {
-      elfcpp::Shdr<size, big_endian> shdr(p);
+      typename This::Shdr shdr(p);
       if (shdr.get_sh_type() == elfcpp::SHT_SYMTAB)
        {
          this->symtab_shnum_ = i;
@@ -136,23 +146,23 @@ Sized_object<size, big_endian>::do_read_symbols()
       Read_symbols_data ret;
       ret.symbols = NULL;
       ret.symbols_size = 0;
-      ret.first_global = 0;
       ret.symbol_names = NULL;
       ret.symbol_names_size = 0;
       return ret;
     }
 
-  const int shdr_size = This::shdr_size;
-
   // Read the symbol table section header.
-  off_t symtabshdroff = this->shoff_ + (this->symtab_shnum_ * shdr_size);
-  const unsigned char* psymtabshdr = this->get_view(symtabshdroff, shdr_size);
-  elfcpp::Shdr<size, big_endian> symtabshdr(psymtabshdr);
+  typename This::Shdr symtabshdr(this->section_header(this->symtab_shnum_));
   assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
 
+  // We only need the external symbols.
+  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;
+
   // Read the symbol table.
-  File_view* fvsymtab = this->get_lasting_view(symtabshdr.get_sh_offset(),
-                                              symtabshdr.get_sh_size());
+  File_view* fvsymtab = this->get_lasting_view(extoff, extsize);
 
   // Read the section header for the symbol names.
   unsigned int strtab_shnum = symtabshdr.get_sh_link();
@@ -162,9 +172,7 @@ Sized_object<size, big_endian>::do_read_symbols()
              program_name, this->name().c_str(), strtab_shnum);
       gold_exit(false);
     }
-  off_t strtabshdroff = this->shoff_ + (strtab_shnum * shdr_size);
-  const unsigned char *pstrtabshdr = this->get_view(strtabshdroff, shdr_size);
-  elfcpp::Shdr<size, big_endian> strtabshdr(pstrtabshdr);
+  typename This::Shdr strtabshdr(this->section_header(strtab_shnum));
   if (strtabshdr.get_sh_type() != elfcpp::SHT_STRTAB)
     {
       fprintf(stderr,
@@ -180,8 +188,7 @@ Sized_object<size, big_endian>::do_read_symbols()
 
   Read_symbols_data ret;
   ret.symbols = fvsymtab;
-  ret.symbols_size = symtabshdr.get_sh_size();
-  ret.first_global = symtabshdr.get_sh_info();
+  ret.symbols_size = extsize;
   ret.symbol_names = fvstrtab;
   ret.symbol_names_size = strtabshdr.get_sh_size();
 
@@ -211,29 +218,14 @@ Sized_object<size, big_endian>::do_add_symbols(Symbol_table* symtab,
       gold_exit(false);
     }
 
-  const char* sym_names =
-    reinterpret_cast<const char*>(sd.symbol_names->data());
-
-  // We only add the global symbols to the symbol table.
-  if (symcount > sd.first_global)
-    {
-      this->symbols_ = new Symbol*[symcount - sd.first_global];
-
-      const unsigned char* symdata = sd.symbols->data();
-      symdata += sd.first_global * sym_size;
-      const elfcpp::Sym<size, big_endian>* syms =
-       reinterpret_cast<const elfcpp::Sym<size, big_endian>*>(symdata);
-
-      symtab->add_from_object(this, syms, symcount - sd.first_global,
-                             sym_names, sd.symbol_names_size, this->symbols_);
-    }
+  this->symbols_ = new Symbol*[symcount];
 
-  // Add the names of the local symbols.  FIXME: We shouldn't do this
-  // if we are stripping symbols.
-  const elfcpp::Sym<size, big_endian>* local_syms =
+  const elfcpp::Sym<size, big_endian>* syms =
     reinterpret_cast<const elfcpp::Sym<size, big_endian>*>(sd.symbols->data());
-  symtab->add_local_symbol_names(this, local_syms, sd.first_global,
-                                sym_names, sd.symbol_names_size);
+  const char* sym_names =
+    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;
@@ -279,9 +271,8 @@ Sized_object<size, big_endian>::include_section_group(
              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);
+
+  typename This::Shdr symshdr(this->section_header(shdr.get_sh_link()));
 
   // Read the symbol table entry.
   if (shdr.get_sh_info() >= symshdr.get_sh_size() / This::sym_size)
@@ -302,10 +293,8 @@ Sized_object<size, big_endian>::include_section_group(
              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);
+
+  typename This::Shdr symnamehdr(this->section_header(symshdr.get_sh_link()));
 
   // Read the symbol table names.
   const unsigned char *psymnamesu = this->get_view(symnamehdr.get_sh_offset(),
@@ -396,7 +385,7 @@ Sized_object<size, big_endian>::do_layout(Layout* layout)
 
   // Get the section names.
   const unsigned char* pshdrnames = pshdrs + this->shstrndx_ * This::shdr_size;
-  elfcpp::Shdr<size, big_endian> shdrnames(pshdrnames);
+  typename This::Shdr 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(),
@@ -411,7 +400,7 @@ Sized_object<size, big_endian>::do_layout(Layout* layout)
 
   for (unsigned int i = 0; i < shnum; ++i)
     {
-      elfcpp::Shdr<size, big_endian> shdr(pshdrs);
+      typename This::Shdr shdr(pshdrs);
 
       if (shdr.get_sh_name() >= names_size)
        {
@@ -456,12 +445,105 @@ Sized_object<size, big_endian>::do_layout(Layout* layout)
     }
 }
 
+// Finalize the local symbols.  Here we record the file offset at
+// which they should be output and we add their names to *POOL.
+// Return the new file offset.  This function is always called from
+// the main thread.  The actual output of the local symbols will occur
+// in a separate task.
+
+template<int size, bool big_endian>
+off_t
+Sized_object<size, big_endian>::do_finalize_local_symbols(off_t off,
+                                                         Stringpool* pool)
+{
+  this->local_symbol_offset_ = off;
+
+  // Read the symbol table section header.
+  typename This::Shdr symtabshdr(this->section_header(this->symtab_shnum_));
+  assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
+
+  // Read the local symbols.
+  unsigned int loccount = symtabshdr.get_sh_info();
+  const int sym_size = This::sym_size;
+  off_t locsize = loccount * sym_size;
+  const unsigned char* psyms = this->get_view(symtabshdr.get_sh_offset(),
+                                             locsize);
+
+  // Read the section header for the symbol names.
+  typename This::Shdr strtabshdr(
+    this->section_header(symtabshdr.get_sh_link()));
+  assert(strtabshdr.get_sh_type() == elfcpp::SHT_STRTAB);
+
+  // Read the symbol names.
+  const unsigned char* pnamesu = this->get_view(strtabshdr.get_sh_offset(),
+                                               strtabshdr.get_sh_size());
+  const char* pnames = reinterpret_cast<const char*>(pnamesu);
+
+  // Loop over the local symbols.
+
+  std::vector<Map_to_output>& mo(this->map_to_output());
+  unsigned int shnum = this->shnum();
+  // Skip the first, dummy, symbol.
+  psyms += sym_size;
+  for (unsigned int i = 1; i < loccount; ++i)
+    {
+      elfcpp::Sym<size, big_endian> sym(psyms);
+
+      unsigned int shndx = sym.get_st_shndx();
+
+      if (shndx >= elfcpp::SHN_LORESERVE)
+       {
+         if (shndx != elfcpp::SHN_ABS)
+           {
+             fprintf(stderr,
+                     _("%s: %s: unknown section index %u "
+                       "for local symbol %u\n"),
+                     program_name, this->name().c_str(), shndx, i);
+             gold_exit(false);
+           }
+         // FIXME: Handle SHN_XINDEX.
+       }
+      else
+       {
+         if (shndx >= shnum)
+           {
+             fprintf(stderr,
+                     _("%s: %s: local symbol %u section index %u "
+                       "out of range\n"),
+                     program_name, this->name().c_str(), i, shndx);
+             gold_exit(false);
+           }
+
+         if (mo[shndx].output_section == NULL)
+           continue;
+       }
+
+      pool->add(pnames + sym.get_st_name());
+      off += sym_size;
+
+      psyms += sym_size;
+    }
+
+  return off;
+}
+
 // Input_objects methods.
 
 void
 Input_objects::add_object(Object* obj)
 {
   this->object_list_.push_back(obj);
+
+  Target* target = obj->target();
+  if (this->target_ == NULL)
+    this->target_ = target;
+  else if (this->target_ != target)
+    {
+      fprintf(stderr, "%s: %s: incompatible target\n",
+             program_name, obj->name().c_str());
+      gold_exit(false);
+    }
+
   if (obj->is_dynamic())
     this->any_dynamic_ = true;
 }
index 36cf949..e3df36d 100644 (file)
@@ -14,6 +14,7 @@
 namespace gold
 {
 
+class Stringpool;
 class Output_section;
 class Layout;
 
@@ -25,8 +26,6 @@ struct Read_symbols_data
   File_view* symbols;
   // Size of symbol data in bytes.
   off_t symbols_size;
-  // Index of first global symbol.
-  unsigned int first_global;
   // Symbol names.
   File_view* symbol_names;
   // Size of symbol name data in bytes.
@@ -110,7 +109,13 @@ class Object
   layout(Layout* lay)
   { this->do_layout(lay); }
 
- protected:
+  // Initial local symbol processing: set the offset where local
+  // symbol information will be stored; add local symbol names to
+  // *POOL; return the offset following the local symbols.
+  off_t
+  finalize_local_symbols(off_t off, Stringpool* pool)
+  { return this->do_finalize_local_symbols(off, pool); }
+
   // 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.
@@ -123,6 +128,13 @@ class Object
     off_t offset;
   };
 
+  // Given a section index, return the corresponding Map_to_output
+  // information.
+  const Map_to_output*
+  section_output_info(unsigned int shnum) const
+  { return &this->map_to_output_[shnum]; }
+
+ protected:
   // Read the symbols--implemented by child class.
   virtual Read_symbols_data
   do_read_symbols() = 0;
@@ -136,6 +148,10 @@ class Object
   virtual void
   do_layout(Layout*) = 0;
 
+  // Finalize local symbols--implemented by child class.
+  virtual off_t
+  do_finalize_local_symbols(off_t, Stringpool*) = 0;
+
   // Get the file.
   Input_file*
   input_file() const
@@ -152,7 +168,7 @@ class Object
 
   // Get the number of sections.
   unsigned int
-  shnum(void) const
+  shnum() const
   { return this->shnum_; }
 
   // Set the number of sections.
@@ -243,6 +259,10 @@ class Sized_object : public Object
   void
   do_layout(Layout*);
 
+  // Finalize the local symbols.
+  off_t
+  do_finalize_local_symbols(off_t, Stringpool*);
+
   // Return the appropriate Sized_target structure.
   Sized_target<size, big_endian>*
   sized_target()
@@ -264,6 +284,11 @@ class Sized_object : public Object
   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;
+  typedef elfcpp::Shdr<size, big_endian> Shdr;
+
+  // Read the section header for section SHNUM.
+  const unsigned char*
+  section_header(unsigned int shnum);
 
   // Whether to include a section group in the link.
   bool
@@ -286,6 +311,8 @@ class Sized_object : public Object
   unsigned int symtab_shnum_;
   // The entries in the symbol table for the external symbols.
   Symbol** symbols_;
+  // File offset for local symbols.
+  off_t local_symbol_offset_;
 };
 
 // A class to manage the list of all objects.
@@ -294,7 +321,7 @@ class Input_objects
 {
  public:
   Input_objects()
-    : object_list_(), any_dynamic_(false)
+    : object_list_(), target_(NULL), any_dynamic_(false)
   { }
 
   // The type of the list of input objects.
@@ -304,6 +331,11 @@ class Input_objects
   void
   add_object(Object*);
 
+  // Get the target we should use for the output file.
+  Target*
+  target() const
+  { return this->target_; }
+
   // Iterate over all objects.
   Object_list::const_iterator
   begin() const
@@ -323,6 +355,7 @@ class Input_objects
   Input_objects& operator=(const Input_objects&);
 
   Object_list object_list_;
+  Target* target_;
   bool any_dynamic_;
 };
 
index 9092301..3940f82 100644 (file)
@@ -3,6 +3,7 @@
 #include "gold.h"
 
 #include <cstdlib>
+#include <algorithm>
 
 #include "object.h"
 #include "output.h"
@@ -16,18 +17,116 @@ Output_data::~Output_data()
 {
 }
 
+// Set the address and offset.
+
+void
+Output_data::set_address(uint64_t addr, off_t off)
+{
+  this->address_ = addr;
+  this->offset_ = off;
+
+  // Let the child class know.
+  this->do_set_address(addr, off);
+}
+
+// Return the default alignment for a size--32 or 64.
+
+uint64_t
+Output_data::default_alignment(int size)
+{
+  if (size == 32)
+    return 4;
+  else if (size == 64)
+    return 8;
+  else
+    abort();
+}
+
 // Output_data_const methods.
 
 void
-Output_data_const::write(Output_file* output, off_t off)
+Output_data_const::do_write(Output_file* output)
+{
+  output->write(this->offset(), data_.data(), data_.size());
+}
+
+// Output_section_header methods.  This currently assumes that the
+// segment and section lists are complete at construction time.
+
+Output_section_headers::Output_section_headers(
+    int size,
+    const Layout::Segment_list& segment_list,
+    const Layout::Section_list& section_list)
+  : size_(size),
+    segment_list_(segment_list),
+    section_list_(section_list)
+{
+  // Count all the sections.
+  off_t count = 0;
+  for (Layout::Segment_list::const_iterator p = segment_list.begin();
+       p != segment_list.end();
+       ++p)
+    count += (*p)->output_section_count();
+  count += section_list.size();
+
+  int shdr_size;
+  if (size == 32)
+    shdr_size = elfcpp::Elf_sizes<32>::shdr_size;
+  else if (size == 64)
+    shdr_size = elfcpp::Elf_sizes<64>::shdr_size;
+  else
+    abort();
+
+  this->set_data_size(count * shdr_size);
+}
+
+void
+Output_section_headers::do_write(Output_file*)
 {
-  output->write(off, data_.data(), data_.size());
+  // FIXME: Unimplemented.
+  abort();
 }
 
 // Output_segment_header methods.
 
 void
-Output_segment_headers::write(Output_file*, off_t)
+Output_segment_headers::do_write(Output_file*)
+{
+  // FIXME: Unimplemented.
+  abort();
+}
+
+// Output_file_header methods.
+
+Output_file_header::Output_file_header(int size,
+                                      const General_options& options,
+                                      const Target* target,
+                                      const Symbol_table* symtab,
+                                      const Output_segment_headers* osh)
+  : size_(size),
+    options_(options),
+    target_(target),
+    symtab_(symtab),
+    program_header_(osh),
+    section_header_(NULL),
+    shstrtab_(NULL)
+{
+}
+
+// Set the section table information for a file header.
+
+void
+Output_file_header::set_section_info(const Output_section_headers* shdrs,
+                                    const Output_section* shstrtab)
+{
+  this->section_header_ = shdrs;
+  this->shstrtab_ = shstrtab;
+}
+
+// Write out the file header.
+
+void
+Output_file_header::do_write(Output_file*)
 {
   // FIXME: Unimplemented.
   abort();
@@ -40,10 +139,8 @@ Output_segment_headers::write(Output_file*, off_t)
 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),
     link_(0),
     info_(0),
     type_(type),
@@ -76,18 +173,49 @@ Output_section::add_input_section(Object* object, const char* secname,
   if (addralign > this->addralign_)
     this->addralign_ = addralign;
 
-  off_t ssize = this->get_size();
+  off_t ssize = this->data_size();
   ssize = (ssize + addralign - 1) &~ (addralign - 1);
 
-  this->set_size(ssize + shdr.get_sh_size());
+  // SHF_TLS/SHT_NOBITS sections are handled specially: they are
+  // treated as having no size and taking up no space.  We only use
+  // the real size when setting the pt_memsz field of the PT_TLS
+  // segment.
+  if ((this->flags_ & elfcpp::SHF_TLS) == 0
+      || this->type_ != elfcpp::SHT_NOBITS)
+    this->set_data_size(ssize + shdr.get_sh_size());
 
   return size;
 }
 
+// Output_section_symtab methods.
+
+Output_section_symtab::Output_section_symtab(const char* name, off_t size)
+  : Output_section(name, elfcpp::SHT_SYMTAB, 0)
+{
+  this->set_data_size(size);
+}
+
+// Output_section_strtab methods.
+
+Output_section_strtab::Output_section_strtab(const char* name,
+                                            Stringpool* contents)
+  : Output_section(name, elfcpp::SHT_STRTAB, 0),
+    contents_(contents)
+{
+}
+
+void
+Output_section_strtab::do_write(Output_file*)
+{
+  // FIXME: Unimplemented.
+  abort();
+}
+
 // Output segment methods.
 
 Output_segment::Output_segment(elfcpp::Elf_Word type, elfcpp::Elf_Word flags)
   : output_data_(),
+    output_bss_(),
     vaddr_(0),
     paddr_(0),
     memsz_(0),
@@ -102,10 +230,22 @@ Output_segment::Output_segment(elfcpp::Elf_Word type, elfcpp::Elf_Word flags)
 // Add an Output_section to an Output_segment.
 
 void
-Output_segment::add_output_section(Output_section* os)
+Output_segment::add_output_section(Output_section* os,
+                                  elfcpp::Elf_Word seg_flags)
 {
-  // Update the segment flags.
-  this->flags_ |= os->flags() & (elfcpp::PF_R | elfcpp::PF_W | elfcpp::PF_X);
+  assert((os->flags() & elfcpp::SHF_ALLOC) != 0);
+
+  // Update the segment flags and alignment.
+  this->flags_ |= seg_flags;
+  uint64_t addralign = os->addralign();
+  if (addralign > this->align_)
+    this->align_ = addralign;
+
+  Output_segment::Output_data_list* pdl;
+  if (os->type() == elfcpp::SHT_NOBITS)
+    pdl = &this->output_bss_;
+  else
+    pdl = &this->output_data_;
 
   // So that PT_NOTE segments will work correctly, we need to ensure
   // that all SHT_NOTE sections are adjacent.  This will normally
@@ -122,37 +262,196 @@ Output_segment::add_output_section(Output_section* os)
 
   if (os->type() == elfcpp::SHT_NOTE)
     {
-      for (Layout::Data_list::iterator p = this->output_data_.begin();
-          p != this->output_data_.end();
-          ++p)
+      Layout::Data_list::iterator p = pdl->end();
+      do
        {
+         --p;
          if ((*p)->is_section_type(elfcpp::SHT_NOTE))
            {
              ++p;
-             this->output_data_.insert(p, os);
+             pdl->insert(p, os);
              return;
            }
        }
+      while (p != pdl->begin());
     }
 
   // Similarly, so that PT_TLS segments will work, we need to group
-  // SHF_TLS sections.
+  // SHF_TLS sections.  An SHF_TLS/SHT_NOBITS section is a special
+  // case: we group the SHF_TLS/SHT_NOBITS sections right after the
+  // SHF_TLS/SHT_PROGBITS sections.  This lets us set up PT_TLS
+  // correctly.
   if ((os->flags() & elfcpp::SHF_TLS) != 0)
     {
-      for (Layout::Data_list::iterator p = this->output_data_.begin();
-          p != this->output_data_.end();
-          ++p)
+      pdl = &this->output_data_;
+      bool nobits = os->type() == elfcpp::SHT_NOBITS;
+      Layout::Data_list::iterator p = pdl->end();
+      do
        {
-         if ((*p)->is_section_flag_set(elfcpp::SHF_TLS))
+         --p;
+         if ((*p)->is_section_flag_set(elfcpp::SHF_TLS)
+             && (nobits || !(*p)->is_section_type(elfcpp::SHT_NOBITS)))
            {
              ++p;
-             this->output_data_.insert(p, os);
+             pdl->insert(p, os);
              return;
            }
        }
+      while (p != pdl->begin());
     }
 
-  this->output_data_.push_back(os);
+  pdl->push_back(os);
+}
+
+// Add an Output_data (which is not an Output_section) to the start of
+// a segment.
+
+void
+Output_segment::add_initial_output_data(Output_data* od)
+{
+  uint64_t addralign = od->addralign();
+  if (addralign > this->align_)
+    this->align_ = addralign;
+
+  this->output_data_.push_front(od);
+}
+
+// Return the maximum alignment of the Output_data in Output_segment.
+// We keep this up to date as we add Output_sections and Output_data.
+
+uint64_t
+Output_segment::max_data_align() const
+{
+  return this->align_;
+}
+
+// Set the section addresses for an Output_segment.  ADDR is the
+// address and *POFF is the file offset.  Return the address of the
+// immediately following segment.  Update *POFF.
+
+uint64_t
+Output_segment::set_section_addresses(uint64_t addr, off_t* poff)
+{
+  assert(this->type_ == elfcpp::PT_LOAD);
+
+  this->vaddr_ = addr;
+  this->paddr_ = addr;
+
+  off_t orig_off = *poff;
+  this->offset_ = orig_off;
+
+  addr = this->set_section_list_addresses(&this->output_data_, addr, poff);
+  this->filesz_ = *poff - orig_off;
+
+  off_t off = *poff;
+
+  return this->set_section_list_addresses(&this->output_bss_, addr, poff);
+  this->memsz_ = *poff - orig_off;
+
+  // Ignore the file offset adjustments made by the BSS Output_data
+  // objects.
+  *poff = off;
+}
+
+// Set the addresses in a list of Output_data structures.
+
+uint64_t
+Output_segment::set_section_list_addresses(Output_data_list* pdl,
+                                          uint64_t addr, off_t* poff)
+{
+  off_t off = *poff;
+
+  for (Output_data_list::iterator p = pdl->begin();
+       p != pdl->end();
+       ++p)
+    {
+      uint64_t addralign = (*p)->addralign();
+      addr = (addr + addralign - 1) & ~ (addralign - 1);
+      off = (off + addralign - 1) & ~ (addralign - 1);
+      (*p)->set_address(addr, off);
+
+      uint64_t size = (*p)->data_size();
+      addr += size;
+      off += size;
+    }
+
+  *poff = off;
+  return addr;
+}
+
+// For a non-PT_LOAD segment, set the offset from the sections, if
+// any.
+
+void
+Output_segment::set_offset()
+{
+  assert(this->type_ != elfcpp::PT_LOAD);
+
+  if (this->output_data_.empty() && this->output_bss_.empty())
+    {
+      this->vaddr_ = 0;
+      this->paddr_ = 0;
+      this->memsz_ = 0;
+      this->align_ = 0;
+      this->offset_ = 0;
+      this->filesz_ = 0;
+      return;
+    }
+
+  const Output_data* first;
+  if (this->output_data_.empty())
+    first = this->output_bss_.front();
+  else
+    first = this->output_data_.front();
+  this->vaddr_ = first->address();
+  this->paddr_ = this->vaddr_;
+  this->offset_ = first->offset();
+
+  if (this->output_data_.empty())
+    this->filesz_ = 0;
+  else
+    {
+      const Output_data* last_data = this->output_data_.back();
+      this->filesz_ = (last_data->address()
+                      + last_data->data_size()
+                      - this->vaddr_);
+    }
+
+  const Output_data* last;
+  if (this->output_bss_.empty())
+    last = this->output_data_.back();
+  else
+    last = this->output_bss_.back();
+  this->memsz_ = (last->address()
+                 + last->data_size()
+                 - this->vaddr_);
+
+  // this->align_ was set as we added items.
+}
+
+// Return the number of Output_sections in an Output_segment.
+
+unsigned int
+Output_segment::output_section_count() const
+{
+  return (this->output_section_count_list(&this->output_data_)
+         + this->output_section_count_list(&this->output_bss_));
+}
+
+// Return the number of Output_sections in an Output_data_list.
+
+unsigned int
+Output_segment::output_section_count_list(const Output_data_list* pdl) const
+{
+  unsigned int count = 0;
+  for (Output_data_list::const_iterator p = pdl->begin();
+       p != pdl->end();
+       ++p)
+    {
+      if ((*p)->is_section())
+       ++count;
+    }
+  return count;
 }
 
 // Output_file methods.
index b0d3f80..25c5b2a 100644 (file)
@@ -3,6 +3,7 @@
 #ifndef GOLD_OUTPUT_H
 #define GOLD_OUTPUT_H
 
+#include <cassert>
 #include <list>
 
 #include "elfcpp.h"
@@ -22,47 +23,113 @@ class Sized_target;
 class Output_data
 {
  public:
-  Output_data(off_t size = 0)
-    : size_(size)
+  explicit Output_data(off_t data_size = 0)
+    : address_(0), data_size_(data_size), offset_(0)
   { }
 
   virtual
   ~Output_data();
 
-  // Return the size of the data.  This can't be called "size" since
-  // that interferes with the widely used template parameter name.
+  // Return the address.
+  uint64_t
+  address() const
+  { return this->address_; }
+
+  // Return the size of the data.
   off_t
-  get_size()
-  { return this->size_; }
+  data_size() const
+  { return this->data_size_; }
+
+  // Return the file offset.
+  off_t
+  offset() const
+  { return this->offset_; }
+
+  // Return the required alignment.
+  uint64_t
+  addralign() const
+  { return this->do_addralign(); }
+
+  // Return whether this is an Output_section.
+  bool
+  is_section() const
+  { return this->do_is_section(); }
+
+  // Return whether this is an Output_section of the specified type.
+  bool
+  is_section_type(elfcpp::Elf_Word stt) const
+  { return this->do_is_section_type(stt); }
+
+  // Return whether this is an Output_section with the specified flag
+  // set.
+  bool
+  is_section_flag_set(elfcpp::Elf_Xword shf) const
+  { return this->do_is_section_flag_set(shf); }
+
+  // Set the address and file offset of this data.
+  void
+  set_address(uint64_t addr, off_t off);
+
+  // Write the data to the output file.
+  void
+  write(Output_file* file)
+  { this->do_write(file); }
 
-  // Write the data to the output file at the specified offset.  This
-  // must be implemented by the real class.
+ protected:
+  // Functions that child classes may or in some cases must implement.
+
+  // Write the data to the output file.
   virtual void
-  write(Output_file*, off_t off) = 0;
+  do_write(Output_file*) = 0;
+
+  // Return the required alignment.
+  virtual uint64_t
+  do_addralign() const = 0;
+
+  // Return whether this is an Output_section.
+  virtual bool
+  do_is_section() const
+  { return false; }
 
   // Return whether this is an Output_section of the specified type.
+  // This only needs to be implement by Output_section.
   virtual bool
-  is_section_type(elfcpp::Elf_Word)
+  do_is_section_type(elfcpp::Elf_Word) const
   { return false; }
 
-  // Return whether this is an Output_section with the specified flag
-  // set.
+  // Return whether this is an Output_section with the specific flag
+  // set.  This only needs to be implemented by Output_section.
   virtual bool
-  is_section_flag_set(elfcpp::Elf_Xword)
+  do_is_section_flag_set(elfcpp::Elf_Xword) const
   { return false; }
 
- protected:
+  // Set the address and file offset of the data.  This only needs to
+  // be implemented if the child needs to know.
+  virtual void
+  do_set_address(uint64_t, off_t)
+  { }
+
+  // Functions that child classes may call.
+
   // Set the size of the data.
   void
-  set_size(off_t size)
-  { this->size_ = size; }
+  set_data_size(off_t data_size)
+  { this->data_size_ = data_size; }
+
+  // Return default alignment for a size--32 or 64.
+  static uint64_t
+  default_alignment(int size);
 
  private:
   Output_data(const Output_data&);
   Output_data& operator=(const Output_data&);
 
+  // Memory address in file (not always meaningful).
+  uint64_t address_;
   // Size of data in file.
-  off_t size_;
+  off_t data_size_;
+  // Offset within file.
+  off_t offset_;
 };
 
 // A simple case of Output_data in which we have constant data to
@@ -71,20 +138,26 @@ class Output_data
 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 std::string& data, uint64_t addralign)
+    : Output_data(data.size()), data_(data), addralign_(addralign)
   { }
 
-  Output_data_const(const char* p, off_t len)
-    : Output_data(len), data_(p, len)
+  Output_data_const(const char* p, off_t len, uint64_t addralign)
+    : Output_data(len), data_(p, len), addralign_(addralign)
   { }
 
   // Write the data to the file.
   void
-  write(Output_file* output, off_t off);
+  do_write(Output_file* output);
+
+  // Return the required alignment.
+  uint64_t
+  do_addralign() const
+  { return this->addralign_; }
 
  private:
   std::string data_;
+  uint64_t addralign_;
 };
 
 // Output the section headers.
@@ -92,14 +165,21 @@ class Output_data_const : public Output_data
 class Output_section_headers : public Output_data
 {
  public:
-  Output_section_headers(const Layout::Segment_list&,
+  Output_section_headers(int size,
+                        const Layout::Segment_list&,
                         const Layout::Section_list&);
 
   // Write the data to the file.
   void
-  write(Output_file*, off_t);
+  do_write(Output_file*);
+
+  // Return the required alignment.
+  uint64_t
+  do_addralign() const
+  { return Output_data::default_alignment(this->size_); }
 
  private:
+  int size_;
   const Layout::Segment_list& segment_list_;
   const Layout::Section_list& section_list_;
 };
@@ -109,15 +189,21 @@ class Output_section_headers : public Output_data
 class Output_segment_headers : public Output_data
 {
  public:
-  Output_segment_headers(const Layout::Segment_list& segment_list)
-    : segment_list_(segment_list)
+  Output_segment_headers(int size, const Layout::Segment_list& segment_list)
+    : size_(size), segment_list_(segment_list)
   { }
 
   // Write the data to the file.
   void
-  write(Output_file*, off_t);
+  do_write(Output_file*);
+
+  // Return the required alignment.
+  uint64_t
+  do_addralign() const
+  { return Output_data::default_alignment(this->size_); }
 
  private:
+  int size_;
   const Layout::Segment_list& segment_list_;
 };
 
@@ -126,18 +212,34 @@ class Output_segment_headers : public Output_data
 class Output_file_header : public Output_data
 {
  public:
-  Output_file_header(const General_options&,
+  Output_file_header(int size,
+                    const General_options&,
                     const Target*,
                     const Symbol_table*,
-                    const Output_segment_headers*,
-                    const Output_section_headers*,
-                    const Output_section* shstrtab);
+                    const Output_segment_headers*);
+
+  // Add information about the section headers.  We lay out the ELF
+  // file header before we create the section headers.
+  void set_section_info(const Output_section_headers*,
+                       const Output_section* shstrtab);
 
   // Write the data to the file.
   void
-  write(Output_file*, off_t);
+  do_write(Output_file*);
+
+  // Return the required alignment.
+  uint64_t
+  do_addralign() const
+  { return Output_data::default_alignment(this->size_); }
+
+  // Set the address and offset--we only implement this for error
+  // checking.
+  void
+  do_set_address(uint64_t, off_t off) const
+  { assert(off == 0); }
 
  private:
+  int size_;
   const General_options& options_;
   const Target* target_;
   const Symbol_table* symtab_;
@@ -178,21 +280,36 @@ class Output_section : public Output_data
   flags() const
   { return this->flags_; }
 
+  // Return the address alignment.
+  uint64_t
+  addralign() const
+  { return this->addralign_; }
+
   // Write the data to the file.  For a typical Output_section, this
   // does nothing.  We write out the data by looping over all the
   // input sections.
   virtual void
-  write(Output_file*, off_t)
+  do_write(Output_file*)
   { }
 
+  // Return the address alignment--function required by parent class.
+  uint64_t
+  do_addralign() const
+  { return this->addralign_; }
+
+  // Return whether this is an Output_section.
+  bool
+  do_is_section() const
+  { return true; }
+
   // Return whether this is a section of the specified type.
   bool
-  is_section_type(elfcpp::Elf_Word type)
+  do_is_section_type(elfcpp::Elf_Word type) const
   { return this->type_ == type; }
 
   // Return whether the specified section flag is set.
   bool
-  is_section_flag_set(elfcpp::Elf_Xword flag)
+  do_is_section_flag_set(elfcpp::Elf_Xword flag) const
   { return (this->flags_ & flag) != 0; }
 
  private:
@@ -200,14 +317,12 @@ class Output_section : public Output_data
 
   // The name of the section.  This will point into a Stringpool.
   const char* name_;
-  // The section address.
-  uint64_t addr_;
+  // The section address is in the parent class.
   // The section alignment.
   uint64_t addralign_;
   // The section entry size.
   uint64_t entsize_;
-  // The file offset.
-  off_t offset_;
+  // The file offset is in the parent class.
   // The section link field.
   unsigned int link_;
   // The section info field.
@@ -224,8 +339,22 @@ class Output_section : public Output_data
 class Output_section_symtab : public Output_section
 {
  public:
-  Output_section_symtab();
-  ~Output_section_symtab();
+  Output_section_symtab(const char* name, off_t size);
+};
+
+// A special Output_section which holds a string table.
+
+class Output_section_strtab : public Output_section
+{
+ public:
+  Output_section_strtab(const char* name, Stringpool* contents);
+
+  // Write out the data.
+  void
+  do_write(Output_file*);
+
+ private:
+  Stringpool* contents_;
 };
 
 // An output segment.  PT_LOAD segments are built from collections of
@@ -258,9 +387,35 @@ class Output_segment
   flags() const
   { return this->flags_; }
 
+  // Return the maximum alignment of the Output_data.
+  uint64_t
+  max_data_align() const;
+
   // Add an Output_section to this segment.
   void
-  add_output_section(Output_section*);
+  add_output_section(Output_section*, elfcpp::Elf_Word seg_flags);
+
+  // Add an Output_data (which is not an Output_section) to the start
+  // of this segment.
+  void
+  add_initial_output_data(Output_data*);
+
+  // Set the address of the segment to ADDR and the offset to *POFF
+  // (aligned if necessary), and set the addresses and offsets of all
+  // contained output sections accordingly.  Return the address of the
+  // immediately following segment.  Update *POFF.  This should only
+  // be called for a PT_LOAD segment.
+  uint64_t
+  set_section_addresses(uint64_t addr, off_t* poff);
+
+  // Set the offset of this segment based on the section.  This should
+  // only be called for a non-PT_LOAD segment.
+  void
+  set_offset();
+
+  // Return the number of output sections.
+  unsigned int
+  output_section_count() const;
 
  private:
   Output_segment(const Output_segment&);
@@ -268,9 +423,18 @@ class Output_segment
 
   typedef std::list<Output_data*> Output_data_list;
 
-  // The list of output sections attached to this segment.  This is
-  // cleared after layout.
+  // Set the section addresses in an Output_data_list.
+  uint64_t
+  set_section_list_addresses(Output_data_list*, uint64_t addr, off_t* poff);
+
+  // Return the number of Output_sections in an Output_data_list.
+  unsigned int
+  output_section_count_list(const Output_data_list*) const;
+
+  // The list of output data with contents attached to this segment.
   Output_data_list output_data_;
+  // The list of output data without contents attached to this segment.
+  Output_data_list output_bss_;
   // The segment virtual address.
   uint64_t vaddr_;
   // The segment physical address.
index ec385f4..b0852a3 100644 (file)
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2006-09-26 14:19-0700\n"
+"POT-Creation-Date: 2006-09-27 15:38-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"
@@ -99,103 +99,113 @@ msgstr ""
 msgid "pthread_cond_signal failed"
 msgstr ""
 
-#: object.cc:54
+#: object.cc:55
 #, c-format
 msgid "%s: %s: bad e_ehsize field (%d != %d)\n"
 msgstr ""
 
-#: object.cc:61
+#: object.cc:62
 #, c-format
 msgid "%s: %s: bad e_shentsize field (%d != %d)\n"
 msgstr ""
 
-#: object.cc:87
+#: object.cc:98
 #, c-format
 msgid "%s: %s: unsupported ELF machine number %d\n"
 msgstr ""
 
-#: object.cc:161
+#: object.cc:171
 #, c-format
 msgid "%s: %s: invalid symbol table name index: %u\n"
 msgstr ""
 
-#: object.cc:171
+#: object.cc:179
 #, c-format
 msgid "%s: %s: symbol table name section has wrong type: %u\n"
 msgstr ""
 
-#: object.cc:209
+#: object.cc:216
 #, c-format
 msgid "%s: %s: size of symbols is not multiple of symbol size\n"
 msgstr ""
 
-#: object.cc:278
+#: object.cc:270
 #, c-format
 msgid "%s: %s: section group %u link %u out of range\n"
 msgstr ""
 
-#: object.cc:289
+#: object.cc:280
 #, c-format
 msgid "%s: %s: section group %u info %u out of range\n"
 msgstr ""
 
-#: object.cc:300
+#: object.cc:291
 #, c-format
 msgid "%s; %s: symtab section %u link %u out of range\n"
 msgstr ""
 
-#: object.cc:318
+#: object.cc:307
 #, c-format
 msgid "%s: %s: symbol %u name offset %u out of range\n"
 msgstr ""
 
-#: object.cc:340
+#: object.cc:329
 #, c-format
 msgid "%s: %s: section %u in section group %u out of range"
 msgstr ""
 
-#: object.cc:419
+#: object.cc:408
 #, c-format
 msgid "%s: %s: bad section name offset for section %u: %lu\n"
 msgstr ""
 
+#: object.cc:499
+#, c-format
+msgid "%s: %s: unknown section index %u for local symbol %u\n"
+msgstr ""
+
+#: object.cc:511
+#, c-format
+msgid "%s: %s: local symbol %u section index %u out of range\n"
+msgstr ""
+
 #. elfcpp::ET_DYN
-#: object.cc:502
+#: object.cc:584
 #, c-format
 msgid "%s: %s: dynamic objects are not yet supported\n"
 msgstr ""
 
-#: object.cc:526 object.cc:579 object.cc:600
+#: object.cc:608 object.cc:661 object.cc:682
 #, c-format
 msgid "%s: %s: ELF file too short\n"
 msgstr ""
 
-#: object.cc:535
+#: object.cc:617
 #, c-format
 msgid "%s: %s: invalid ELF version 0\n"
 msgstr ""
 
-#: object.cc:538
+#: object.cc:620
 #, c-format
 msgid "%s: %s: unsupported ELF version %d\n"
 msgstr ""
 
-#: object.cc:546
+#: object.cc:628
 #, c-format
 msgid "%s: %s: invalid ELF class 0\n"
 msgstr ""
 
-#: object.cc:553
+#: object.cc:635
 #, c-format
 msgid "%s: %s: unsupported ELF class %d\n"
 msgstr ""
 
-#: object.cc:561
+#: object.cc:643
 #, c-format
 msgid "%s: %s: invalid ELF data encoding\n"
 msgstr ""
 
-#: object.cc:568
+#: object.cc:650
 #, c-format
 msgid "%s: %s: unsupported ELF data encoding %d\n"
 msgstr ""
@@ -250,32 +260,27 @@ msgstr ""
 msgid "%s: -%c: %s\n"
 msgstr ""
 
-#: output.cc:70
+#: output.cc:167
 #, c-format
 msgid "%s: %s: invalid alignment %lu for section \"%s\"\n"
 msgstr ""
 
-#: resolve.cc:135
+#: resolve.cc:144
 #, c-format
 msgid "%s: %s: invalid STB_LOCAL symbol %s in external symbols\n"
 msgstr ""
 
-#: resolve.cc:141
+#: resolve.cc:150
 #, c-format
 msgid "%s: %s: unsupported symbol binding %d for symbol %s\n"
 msgstr ""
 
-#: symtab.cc:271
+#: symtab.cc:322
 #, c-format
 msgid "%s: %s: mixing 32-bit and 64-bit ELF objects\n"
 msgstr ""
 
-#: symtab.cc:285
+#: symtab.cc:336
 #, c-format
 msgid "%s: %s: bad global symbol name offset %u at %lu\n"
 msgstr ""
-
-#: symtab.cc:342
-#, c-format
-msgid "%s: %s: bad local symbol name offset %u at %lu\n"
-msgstr ""
index 189032d..a317f99 100644 (file)
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "object.h"
+#include "output.h"
 #include "symtab.h"
 
 namespace gold
@@ -52,7 +53,7 @@ Sized_symbol<size>::init(const char* name, const char* version, Object* object,
 // Class Symbol_table.
 
 Symbol_table::Symbol_table()
-  : size_(0), table_(), namepool_(), output_pool_(), forwarders_()
+  : size_(0), offset_(0), table_(), namepool_(), forwarders_()
 {
 }
 
@@ -371,32 +372,58 @@ Symbol_table::add_from_object(
     }
 }
 
-// Record the names of the local symbols for an object.
+// Set the final values for all the symbols.  Record the file offset
+// OFF.  Add their names to POOL.  Return the new file offset.
 
-template<int size, bool big_endian>
-void
-Symbol_table::add_local_symbol_names(Sized_object<size, big_endian>* object,
-                                    const elfcpp::Sym<size, big_endian>* syms,
-                                    size_t count, const char* sym_names,
-                                    size_t sym_name_size)
+off_t
+Symbol_table::finalize(off_t off, Stringpool* pool)
 {
-  const unsigned char* p = reinterpret_cast<const unsigned char*>(syms);
-  for (size_t i = 0; i < count; ++i)
+  if (this->size_ == 32)
+    return this->sized_finalize<32>(off, pool);
+  else
+    return this->sized_finalize<64>(off, pool);
+}
+
+// Set the final value for all the symbols.
+
+template<int size>
+off_t
+Symbol_table::sized_finalize(off_t off, Stringpool* pool)
+{
+  off = (off + size - 1) & ~ (size - 1);
+  this->offset_ = off;
+
+  const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+  Symbol_table_type::iterator p = this->table_.begin();
+  while (p != this->table_.end())
     {
-      elfcpp::Sym<size, big_endian> sym(p);
+      Sized_symbol<size>* sym = static_cast<Sized_symbol<size>*>(p->second);
 
-      unsigned int st_name = sym.get_st_name();
-      if (st_name >= sym_name_size)
+      // FIXME: Here we need to decide which symbols should go into
+      // the output file.
+
+      const Object::Map_to_output* mo =
+       sym->object()->section_output_info(sym->shnum());
+
+      if (mo->output_section == NULL)
        {
-         fprintf(stderr,
-                 _("%s: %s: bad local symbol name offset %u at %lu\n"),
-                 program_name, object->name().c_str(), st_name,
-                 static_cast<unsigned long>(i));
-         gold_exit(false);
+         // We should be able to erase this symbol from the symbol
+         // table, but at least with gcc 4.0.2
+         // std::unordered_map::erase doesn't appear to return the
+         // new iterator.
+         // p = this->table_.erase(p);
+         ++p;
+       }
+      else
+       {
+         sym->set_value(mo->output_section->address() + mo->offset);
+         pool->add(sym->name());
+         ++p;
+         off += sym_size;
        }
-
-      this->output_pool_.add(sym_names + st_name);
     }
+
+  return off;
 }
 
 // Instantiate the templates we need.  We could use the configure
@@ -443,40 +470,4 @@ Symbol_table::add_from_object<64, false>(
     size_t sym_name_size,
     Symbol** sympointers);
 
-template
-void
-Symbol_table::add_local_symbol_names<32, true>(
-    Sized_object<32, true>* object,
-    const elfcpp::Sym<32, true>* syms,
-    size_t count,
-    const char* sym_names,
-    size_t sym_name_size);
-
-template
-void
-Symbol_table::add_local_symbol_names<32, false>(
-    Sized_object<32, false>* object,
-    const elfcpp::Sym<32, false>* syms,
-    size_t count,
-    const char* sym_names,
-    size_t sym_name_size);
-
-template
-void
-Symbol_table::add_local_symbol_names<64, true>(
-    Sized_object<64, true>* object,
-    const elfcpp::Sym<64, true>* syms,
-    size_t count,
-    const char* sym_names,
-    size_t sym_name_size);
-
-template
-void
-Symbol_table::add_local_symbol_names<64, false>(
-    Sized_object<64, false>* object,
-    const elfcpp::Sym<64, false>* syms,
-    size_t count,
-    const char* sym_names,
-    size_t sym_name_size);
-
 } // End namespace gold.
index 09aff03..91a1f4d 100644 (file)
@@ -182,6 +182,12 @@ class Sized_symbol : public Symbol
   symsize() const
   { return this->size_; }
 
+  // Set the symbol value.  This is called when we store the final
+  // values of the symbols into the symbol table.
+  void
+  set_value(Value_type value)
+  { this->value_ = value; }
+
  private:
   Sized_symbol(const Sized_symbol&);
   Sized_symbol& operator=(const Sized_symbol&);
@@ -230,13 +236,12 @@ class Symbol_table
   const Sized_symbol<size>*
   get_sized_symbol(const Symbol*) const;
 
-  // Record the names of the local symbols for an object.
-  template<int size, bool big_endian>
-  void
-  add_local_symbol_names(Sized_object<size, big_endian>* object,
-                        const elfcpp::Sym<size, big_endian>* syms,
-                        size_t count, const char* sym_names,
-                        size_t sym_name_size);
+  // Finalize the symbol table after we have set the final addresses
+  // of all the input sections.  This sets the final symbol values and
+  // adds the names to *POOL.  It records the file offset OFF, and
+  // returns the new file offset.
+  off_t
+  finalize(off_t, Stringpool*);
 
  private:
   Symbol_table(const Symbol_table&);
@@ -276,6 +281,11 @@ class Symbol_table
           bool big_endian);
 #endif
 
+  // Finalize symbols specialized for size.
+  template<int size>
+  off_t
+  sized_finalize(off_t, Stringpool*);
+
   // The type of the symbol hash table.
 
   typedef std::pair<const char*, const char*> Symbol_table_key;
@@ -298,6 +308,10 @@ class Symbol_table
   // The size of the symbols in the symbol table (32 or 64).
   int size_;
 
+  // The file offset within the output symtab section where we should
+  // write the table.
+  off_t offset_;
+
   // The symbol hash table.
   Symbol_table_type table_;
 
@@ -305,11 +319,6 @@ class Symbol_table
   // Entries in the hash table point into this pool.
   Stringpool namepool_;
 
-  // A pool of symbol names to go into the output file.  This is used
-  // for all symbols, global and local, but only the names of symbols
-  // which will definitely be output are added to this pool.
-  Stringpool output_pool_;
-
   // Forwarding symbols.
   Unordered_map<Symbol*, Symbol*> forwarders_;
 };
index 161c75d..bba3d5a 100644 (file)
@@ -13,6 +13,8 @@
 #ifndef GOLD_TARGET_H
 #define GOLD_TARGET_H
 
+#include <cassert>
+
 #include "symtab.h"
 #include "elfcpp.h"
 
@@ -33,43 +35,70 @@ class Target
   // return 32 or 64.
   int
   get_size() const
-  { return this->size_; }
+  { return this->pti_->size; }
 
   // Return whether this target is big-endian.
   bool
   is_big_endian() const
-  { return this->is_big_endian_; }
+  { return this->pti_->is_big_endian; }
 
   // Whether this target has a specific make_symbol function.
   bool
   has_make_symbol() const
-  { return this->has_make_symbol_; }
+  { return this->pti_->has_make_symbol; }
 
   // Whether this target has a specific resolve function.
   bool
   has_resolve() const
-  { return this->has_resolve_; }
+  { return this->pti_->has_resolve; }
+
+  // Return the default address to use for the text segment.
+  uint64_t
+  text_segment_address() const
+  { return this->pti_->text_segment_address; }
+
+  // Return the ABI specified page size.
+  uint64_t
+  abi_pagesize() const
+  { return this->pti_->abi_pagesize; }
+
+  // Return the common page size used on actual systems.
+  uint64_t
+  common_pagesize() const
+  { return this->pti_->common_pagesize; }
 
  protected:
-  Target(int size, bool is_big_endian, bool has_make_symbol, bool has_resolve)
-    : size_(size),
-      is_big_endian_(is_big_endian),
-      has_make_symbol_(has_make_symbol),
-      has_resolve_(has_resolve)
+  // This struct holds the constant information for a child class.  We
+  // use a struct to avoid the overhead of virtual function calls for
+  // simple information.
+  struct Target_info
+  {
+    // Address size (32 or 64).
+    int size;
+    // Whether the target is big endian.
+    bool is_big_endian;
+    // Whether this target has a specific make_symbol function.
+    bool has_make_symbol;
+    // Whether this target has a specific resolve function.
+    bool has_resolve;
+    // The default text segment address.
+    uint64_t text_segment_address;
+    // The ABI specified page size.
+    uint64_t abi_pagesize;
+    // The common page size used by actual implementations.
+    uint64_t common_pagesize;
+  };
+
+  Target(const Target_info* pti)
+    : pti_(pti)
   { }
 
  private:
   Target(const Target&);
   Target& operator=(const Target&);
 
-  // The target size.
-  int size_;
-  // Whether this target is big endian.
-  bool is_big_endian_;
-  // Whether this target has a special make_symbol function.
-  bool has_make_symbol_;
-  // Whether this target has a special resolve function.
-  bool has_resolve_;
+  // The target information.
+  const Target_info* pti_;
 };
 
 // The abstract class for a specific size and endianness of target.
@@ -96,9 +125,12 @@ class Sized_target : public Target
   { abort(); }
 
  protected:
-  Sized_target(bool has_make_symbol, bool has_resolve)
-    : Target(size, big_endian, has_make_symbol, has_resolve)
-  { }
+  Sized_target(const Target::Target_info* pti)
+    : Target(pti)
+  {
+    assert(pti->size == size);
+    assert(pti->is_big_endian ? big_endian : !big_endian);
+  }
 };
 
 } // End namespace gold.