From Craig Silverstein: Clean up DWARF line reader code.
[deliverable/binutils-gdb.git] / gold / output.cc
index 2a7400def77ca342530fde4e203532150d153cc8..b1917257f2bdc8ffed4acbd1f606217737fcc6d3 100644 (file)
@@ -1,5 +1,25 @@
 // output.cc -- manage the output file for gold
 
+// Copyright 2006, 2007 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// This file is part of gold.
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+// MA 02110-1301, USA.
+
 #include "gold.h"
 
 #include <cstdlib>
@@ -7,8 +27,11 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include <sys/mman.h>
+#include <sys/stat.h>
 #include <algorithm>
+#include "libiberty.h"   // for unlink_if_ordinary()
 
+#include "parameters.h"
 #include "object.h"
 #include "symtab.h"
 #include "reloc.h"
@@ -40,10 +63,18 @@ Output_data::set_address(uint64_t addr, off_t off)
   this->do_set_address(addr, off);
 }
 
+// Return the default alignment for the target size.
+
+uint64_t
+Output_data::default_alignment()
+{
+  return Output_data::default_alignment_for_size(parameters->get_size());
+}
+
 // Return the default alignment for a size--32 or 64.
 
 uint64_t
-Output_data::default_alignment(int size)
+Output_data::default_alignment_for_size(int size)
 {
   if (size == 32)
     return 4;
@@ -57,15 +88,11 @@ Output_data::default_alignment(int size)
 // segment and section lists are complete at construction time.
 
 Output_section_headers::Output_section_headers(
-    int size,
-    bool big_endian,
     const Layout* layout,
     const Layout::Segment_list* segment_list,
     const Layout::Section_list* unattached_section_list,
     const Stringpool* secnamepool)
-  : size_(size),
-    big_endian_(big_endian),
-    layout_(layout),
+  : layout_(layout),
     segment_list_(segment_list),
     unattached_section_list_(unattached_section_list),
     secnamepool_(secnamepool)
@@ -79,6 +106,7 @@ Output_section_headers::Output_section_headers(
       count += (*p)->output_section_count();
   count += unattached_section_list->size();
 
+  const int size = parameters->get_size();
   int shdr_size;
   if (size == 32)
     shdr_size = elfcpp::Elf_sizes<32>::shdr_size;
@@ -95,19 +123,43 @@ Output_section_headers::Output_section_headers(
 void
 Output_section_headers::do_write(Output_file* of)
 {
-  if (this->size_ == 32)
+  if (parameters->get_size() == 32)
     {
-      if (this->big_endian_)
-       this->do_sized_write<32, true>(of);
+      if (parameters->is_big_endian())
+       {
+#ifdef HAVE_TARGET_32_BIG
+         this->do_sized_write<32, true>(of);
+#else
+         gold_unreachable();
+#endif
+       }
       else
-       this->do_sized_write<32, false>(of);
+       {
+#ifdef HAVE_TARGET_32_LITTLE
+         this->do_sized_write<32, false>(of);
+#else
+         gold_unreachable();
+#endif
+       }
     }
-  else if (this->size_ == 64)
+  else if (parameters->get_size() == 64)
     {
-      if (this->big_endian_)
-       this->do_sized_write<64, true>(of);
+      if (parameters->is_big_endian())
+       {
+#ifdef HAVE_TARGET_64_BIG
+         this->do_sized_write<64, true>(of);
+#else
+         gold_unreachable();
+#endif
+       }
       else
-       this->do_sized_write<64, false>(of);
+       {
+#ifdef HAVE_TARGET_64_LITTLE
+         this->do_sized_write<64, false>(of);
+#else
+         gold_unreachable();
+#endif
+       }
     }
   else
     gold_unreachable();
@@ -164,11 +216,10 @@ Output_section_headers::do_sized_write(Output_file* of)
 // Output_segment_header methods.
 
 Output_segment_headers::Output_segment_headers(
-    int size,
-    bool big_endian,
     const Layout::Segment_list& segment_list)
-  : size_(size), big_endian_(big_endian), segment_list_(segment_list)
+  : segment_list_(segment_list)
 {
+  const int size = parameters->get_size();
   int phdr_size;
   if (size == 32)
     phdr_size = elfcpp::Elf_sizes<32>::phdr_size;
@@ -183,19 +234,43 @@ Output_segment_headers::Output_segment_headers(
 void
 Output_segment_headers::do_write(Output_file* of)
 {
-  if (this->size_ == 32)
+  if (parameters->get_size() == 32)
     {
-      if (this->big_endian_)
-       this->do_sized_write<32, true>(of);
+      if (parameters->is_big_endian())
+       {
+#ifdef HAVE_TARGET_32_BIG
+         this->do_sized_write<32, true>(of);
+#else
+         gold_unreachable();
+#endif
+       }
       else
+       {
+#ifdef HAVE_TARGET_32_LITTLE
        this->do_sized_write<32, false>(of);
+#else
+       gold_unreachable();
+#endif
+       }
     }
-  else if (this->size_ == 64)
+  else if (parameters->get_size() == 64)
     {
-      if (this->big_endian_)
-       this->do_sized_write<64, true>(of);
+      if (parameters->is_big_endian())
+       {
+#ifdef HAVE_TARGET_64_BIG
+         this->do_sized_write<64, true>(of);
+#else
+         gold_unreachable();
+#endif
+       }
       else
-       this->do_sized_write<64, false>(of);
+       {
+#ifdef HAVE_TARGET_64_LITTLE
+         this->do_sized_write<64, false>(of);
+#else
+         gold_unreachable();
+#endif
+       }
     }
   else
     gold_unreachable();
@@ -224,21 +299,16 @@ Output_segment_headers::do_sized_write(Output_file* of)
 
 // Output_file_header methods.
 
-Output_file_header::Output_file_header(int size,
-                                      bool big_endian,
-                                      const General_options& options,
-                                      const Target* target,
+Output_file_header::Output_file_header(const Target* target,
                                       const Symbol_table* symtab,
                                       const Output_segment_headers* osh)
-  : size_(size),
-    big_endian_(big_endian),
-    options_(options),
-    target_(target),
+  : target_(target),
     symtab_(symtab),
     segment_header_(osh),
     section_header_(NULL),
     shstrtab_(NULL)
 {
+  const int size = parameters->get_size();
   int ehdr_size;
   if (size == 32)
     ehdr_size = elfcpp::Elf_sizes<32>::ehdr_size;
@@ -265,19 +335,43 @@ Output_file_header::set_section_info(const Output_section_headers* shdrs,
 void
 Output_file_header::do_write(Output_file* of)
 {
-  if (this->size_ == 32)
+  if (parameters->get_size() == 32)
     {
-      if (this->big_endian_)
-       this->do_sized_write<32, true>(of);
+      if (parameters->is_big_endian())
+       {
+#ifdef HAVE_TARGET_32_BIG
+         this->do_sized_write<32, true>(of);
+#else
+         gold_unreachable();
+#endif
+       }
       else
-       this->do_sized_write<32, false>(of);
+       {
+#ifdef HAVE_TARGET_32_LITTLE
+         this->do_sized_write<32, false>(of);
+#else
+         gold_unreachable();
+#endif
+       }
     }
-  else if (this->size_ == 64)
+  else if (parameters->get_size() == 64)
     {
-      if (this->big_endian_)
-       this->do_sized_write<64, true>(of);
+      if (parameters->is_big_endian())
+       {
+#ifdef HAVE_TARGET_64_BIG
+         this->do_sized_write<64, true>(of);
+#else
+         gold_unreachable();
+#endif
+       }
       else
-       this->do_sized_write<64, false>(of);
+       {
+#ifdef HAVE_TARGET_64_LITTLE
+         this->do_sized_write<64, false>(of);
+#else
+         gold_unreachable();
+#endif
+       }
     }
   else
     gold_unreachable();
@@ -315,9 +409,10 @@ Output_file_header::do_sized_write(Output_file* of)
   oehdr.put_e_ident(e_ident);
 
   elfcpp::ET e_type;
-  // FIXME: ET_DYN.
-  if (this->options_.is_relocatable())
+  if (parameters->output_is_object())
     e_type = elfcpp::ET_REL;
+  else if (parameters->output_is_shared())
+    e_type = elfcpp::ET_DYN;
   else
     e_type = elfcpp::ET_EXEC;
   oehdr.put_e_type(e_type);
@@ -445,6 +540,11 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::get_symbol_index()
        index = this->u1_.os->symtab_index();
       break;
 
+    case 0:
+      // Relocations without symbols use a symbol index of 0.
+      index = 0;
+      break;
+
     default:
       if (dynamic)
        {
@@ -477,7 +577,14 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::write_rel(
       Output_section* os = this->u2_.relobj->output_section(this->shndx_,
                                                            &off);
       gold_assert(os != NULL);
-      address += os->address() + off;
+      if (off != -1)
+       address += os->address() + off;
+      else
+       {
+         address = os->output_address(this->u2_.relobj, this->shndx_,
+                                      address);
+         gold_assert(address != -1U);
+       }
     }
   else if (this->u2_.od != NULL)
     address += this->u2_.od->address();
@@ -564,9 +671,7 @@ Output_data_reloc_base<sh_type, dynamic, size, big_endian>::do_write(
 
 template<int size, bool big_endian>
 void
-Output_data_got<size, big_endian>::Got_entry::write(
-    const General_options* options,
-    unsigned char* pov) const
+Output_data_got<size, big_endian>::Got_entry::write(unsigned char* pov) const
 {
   Valtype val = 0;
 
@@ -579,8 +684,11 @@ Output_data_got<size, big_endian>::Got_entry::write(
        // If the symbol is resolved locally, we need to write out its
        // value.  Otherwise we just write zero.  The target code is
        // responsible for creating a relocation entry to fill in the
-       // value at runtime.
-       if (gsym->final_value_is_known(options))
+       // value at runtime. For non-preemptible symbols in a shared
+       // library, the target will need to record whether or not the
+       // value should be written (e.g., it may use a RELATIVE
+       // relocation type).
+       if (gsym->final_value_is_known() || gsym->needs_value_in_got())
          {
            Sized_symbol<size>* sgsym;
            // This cast is a bit ugly.  We don't want to put a
@@ -597,7 +705,8 @@ Output_data_got<size, big_endian>::Got_entry::write(
       break;
 
     default:
-      gold_unreachable();
+      val = this->u_.object->local_symbol_value(this->local_sym_index_);
+      break;
     }
 
   elfcpp::Swap<size, big_endian>::writeval(pov, val);
@@ -622,6 +731,24 @@ Output_data_got<size, big_endian>::add_global(Symbol* gsym)
   return true;
 }
 
+// Add an entry for a local symbol to the GOT.  This returns true if
+// this is a new GOT entry, false if the symbol already has a GOT
+// entry.
+
+template<int size, bool big_endian>
+bool
+Output_data_got<size, big_endian>::add_local(
+    Sized_relobj<size, big_endian>* object,
+    unsigned int symndx)
+{
+  if (object->local_has_got_offset(symndx))
+    return false;
+  this->entries_.push_back(Got_entry(object, symndx));
+  this->set_got_size();
+  object->set_local_got_offset(symndx, this->last_got_offset());
+  return true;
+}
+
 // Write out the GOT.
 
 template<int size, bool big_endian>
@@ -639,7 +766,7 @@ Output_data_got<size, big_endian>::do_write(Output_file* of)
        p != this->entries_.end();
        ++p)
     {
-      p->write(this->options_, pov);
+      p->write(pov);
       pov += add;
     }
 
@@ -705,9 +832,9 @@ Output_data_dynamic::Dynamic_entry::write(
 void
 Output_data_dynamic::do_adjust_output_section(Output_section* os)
 {
-  if (this->target_->get_size() == 32)
+  if (parameters->get_size() == 32)
     os->set_entsize(elfcpp::Elf_sizes<32>::dyn_size);
-  else if (this->target_->get_size() == 64)
+  else if (parameters->get_size() == 64)
     os->set_entsize(elfcpp::Elf_sizes<64>::dyn_size);
   else
     gold_unreachable();
@@ -722,9 +849,9 @@ Output_data_dynamic::do_set_address(uint64_t, off_t)
   this->add_constant(elfcpp::DT_NULL, 0);
 
   int dyn_size;
-  if (this->target_->get_size() == 32)
+  if (parameters->get_size() == 32)
     dyn_size = elfcpp::Elf_sizes<32>::dyn_size;
-  else if (this->target_->get_size() == 64)
+  else if (parameters->get_size() == 64)
     dyn_size = elfcpp::Elf_sizes<64>::dyn_size;
   else
     gold_unreachable();
@@ -736,19 +863,43 @@ Output_data_dynamic::do_set_address(uint64_t, off_t)
 void
 Output_data_dynamic::do_write(Output_file* of)
 {
-  if (this->target_->get_size() == 32)
+  if (parameters->get_size() == 32)
     {
-      if (this->target_->is_big_endian())
-       this->sized_write<32, true>(of);
+      if (parameters->is_big_endian())
+       {
+#ifdef HAVE_TARGET_32_BIG
+         this->sized_write<32, true>(of);
+#else
+         gold_unreachable();
+#endif
+       }
       else
-       this->sized_write<32, false>(of);
+       {
+#ifdef HAVE_TARGET_32_LITTLE
+         this->sized_write<32, false>(of);
+#else
+         gold_unreachable();
+#endif
+       }
     }
-  else if (this->target_->get_size() == 64)
+  else if (parameters->get_size() == 64)
     {
-      if (this->target_->is_big_endian())
-       this->sized_write<64, true>(of);
+      if (parameters->is_big_endian())
+       {
+#ifdef HAVE_TARGET_64_BIG
+         this->sized_write<64, true>(of);
+#else
+         gold_unreachable();
+#endif
+       }
       else
-       this->sized_write<64, false>(of);
+       {
+#ifdef HAVE_TARGET_64_LITTLE
+         this->sized_write<64, false>(of);
+#else
+         gold_unreachable();
+#endif
+       }
     }
   else
     gold_unreachable();
@@ -808,26 +959,25 @@ Output_section::Input_section::set_address(uint64_t addr, off_t off,
     this->u2_.posd->set_address(addr, off);
 }
 
-// Try to turn an input address into an output address.
+// Try to turn an input offset into an output offset.
 
 bool
-Output_section::Input_section::output_address(const Relobj* object,
-                                             unsigned int shndx,
-                                             off_t offset,
-                                             uint64_t output_section_address,
-                                             uint64_t *poutput) const
+Output_section::Input_section::output_offset(const Relobj* object,
+                                            unsigned int shndx,
+                                            off_t offset,
+                                            off_t *poutput) const
 {
   if (!this->is_input_section())
-    return this->u2_.posd->output_address(object, shndx, offset,
-                                         output_section_address, poutput);
+    return this->u2_.posd->output_offset(object, shndx, offset, poutput);
   else
     {
-      if (this->u2_.object != object)
+      if (this->shndx_ != shndx || this->u2_.object != object)
        return false;
       off_t output_offset;
       Output_section* os = object->output_section(shndx, &output_offset);
       gold_assert(os != NULL);
-      *poutput = output_section_address + output_offset + offset;
+      gold_assert(output_offset != -1);
+      *poutput = output_offset + offset;
       return true;
     }
 }
@@ -858,15 +1008,17 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
     info_(0),
     type_(type),
     flags_(flags),
-    out_shndx_(0),
+    out_shndx_(-1U),
     symtab_index_(0),
     dynsym_index_(0),
     input_sections_(),
     first_input_offset_(0),
+    fills_(),
     needs_symtab_index_(false),
     needs_dynsym_index_(false),
     should_link_to_symtab_(false),
-    should_link_to_dynsym_(false)
+    should_link_to_dynsym_(false),
+    after_input_sections_(false)
 {
 }
 
@@ -886,56 +1038,85 @@ Output_section::set_entsize(uint64_t v)
 }
 
 // Add the input section SHNDX, with header SHDR, named SECNAME, in
-// OBJECT, to the Output_section.  Return the offset of the input
-// section within the output section.  We don't always keep track of
-// input sections for an Output_section.  Instead, each Object keeps
-// track of the Output_section for each of its input sections.
+// OBJECT, to the Output_section.  RELOC_SHNDX is the index of a
+// relocation section which applies to this section, or 0 if none, or
+// -1U if more than one.  Return the offset of the input section
+// within the output section.  Return -1 if the input section will
+// receive special handling.  In the normal case we don't always 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(Relobj* object, unsigned int shndx,
+Output_section::add_input_section(Sized_relobj<size, big_endian>* object,
+                                 unsigned int shndx,
                                  const char* secname,
-                                 const elfcpp::Shdr<size, big_endian>& shdr)
+                                 const elfcpp::Shdr<size, big_endian>& shdr,
+                                 unsigned int reloc_shndx)
 {
   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);
+      object->error(_("invalid alignment %lu for section \"%s\""),
+                   static_cast<unsigned long>(addralign), secname);
+      addralign = 1;
     }
 
   if (addralign > this->addralign_)
     this->addralign_ = addralign;
 
   // If this is a SHF_MERGE section, we pass all the input sections to
-  // a Output_data_merge.
-  if ((shdr.get_sh_flags() & elfcpp::SHF_MERGE) != 0)
+  // a Output_data_merge.  We don't try to handle relocations for such
+  // a section.
+  if ((shdr.get_sh_flags() & elfcpp::SHF_MERGE) != 0
+      && reloc_shndx == 0)
     {
       if (this->add_merge_input_section(object, shndx, shdr.get_sh_flags(),
                                        shdr.get_sh_entsize(),
                                        addralign))
        {
          // Tell the relocation routines that they need to call the
-         // output_address method to determine the final address.
+         // output_offset method to determine the final address.
          return -1;
        }
     }
 
-  off_t ssize = this->data_size();
-  ssize = align_address(ssize, addralign);
-  this->set_data_size(ssize + shdr.get_sh_size());
+  off_t offset_in_section = this->data_size();
+  off_t aligned_offset_in_section = align_address(offset_in_section,
+                                                  addralign);
+
+  if (aligned_offset_in_section > offset_in_section
+      && (shdr.get_sh_flags() & elfcpp::SHF_EXECINSTR) != 0
+      && object->target()->has_code_fill())
+    {
+      // We need to add some fill data.  Using fill_list_ when
+      // possible is an optimization, since we will often have fill
+      // sections without input sections.
+      off_t fill_len = aligned_offset_in_section - offset_in_section;
+      if (this->input_sections_.empty())
+        this->fills_.push_back(Fill(offset_in_section, fill_len));
+      else
+        {
+          // FIXME: When relaxing, the size needs to adjust to
+          // maintain a constant alignment.
+          std::string fill_data(object->target()->code_fill(fill_len));
+          Output_data_const* odc = new Output_data_const(fill_data, 1);
+          this->input_sections_.push_back(Input_section(odc));
+        }
+    }
+
+  this->set_data_size(aligned_offset_in_section + shdr.get_sh_size());
 
   // We need to keep track of this section if we are already keeping
   // track of sections, or if we are relaxing.  FIXME: Add test for
   // relaxing.
-  if (! this->input_sections_.empty())
+  if (!this->input_sections_.empty())
     this->input_sections_.push_back(Input_section(object, shndx,
                                                  shdr.get_sh_size(),
                                                  addralign));
 
-  return ssize;
+  return aligned_offset_in_section;
 }
 
 // Add arbitrary data to an output section.
@@ -981,17 +1162,18 @@ Output_section::add_merge_input_section(Relobj* object, unsigned int shndx,
                                        uint64_t flags, uint64_t entsize,
                                        uint64_t addralign)
 {
-  // We only merge constants if the alignment is not more than the
-  // entry size.  This could be handled, but it's unusual.
-  if (addralign > entsize)
+  bool is_string = (flags & elfcpp::SHF_STRINGS) != 0;
+
+  // We only merge strings if the alignment is not more than the
+  // character size.  This could be handled, but it's unusual.
+  if (is_string && addralign > entsize)
     return false;
 
-  bool is_string = (flags & elfcpp::SHF_STRINGS) != 0;
   Input_section_list::iterator p;
   for (p = this->input_sections_.begin();
        p != this->input_sections_.end();
        ++p)
-    if (p->is_merge_section(is_string, entsize))
+    if (p->is_merge_section(is_string, entsize, addralign))
       break;
 
   // We handle the actual constant merging in Output_merge_data or
@@ -1002,13 +1184,13 @@ Output_section::add_merge_input_section(Relobj* object, unsigned int shndx,
     {
       Output_section_data* posd;
       if (!is_string)
-       posd = new Output_merge_data(entsize);
+       posd = new Output_merge_data(entsize, addralign);
       else if (entsize == 1)
-       posd = new Output_merge_string<char>();
+       posd = new Output_merge_string<char>(addralign);
       else if (entsize == 2)
-       posd = new Output_merge_string<uint16_t>();
+       posd = new Output_merge_string<uint16_t>(addralign);
       else if (entsize == 4)
-       posd = new Output_merge_string<uint32_t>();
+       posd = new Output_merge_string<uint32_t>(addralign);
       else
        return false;
 
@@ -1019,6 +1201,57 @@ Output_section::add_merge_input_section(Relobj* object, unsigned int shndx,
   return true;
 }
 
+// Given an address OFFSET relative to the start of input section
+// SHNDX in OBJECT, return whether this address is being included in
+// the final link.  This should only be called if SHNDX in OBJECT has
+// a special mapping.
+
+bool
+Output_section::is_input_address_mapped(const Relobj* object,
+                                       unsigned int shndx,
+                                       off_t offset) const
+{
+  gold_assert(object->is_section_specially_mapped(shndx));
+
+  for (Input_section_list::const_iterator p = this->input_sections_.begin();
+       p != this->input_sections_.end();
+       ++p)
+    {
+      off_t output_offset;
+      if (p->output_offset(object, shndx, offset, &output_offset))
+       return output_offset != -1;
+    }
+
+  // By default we assume that the address is mapped.  This should
+  // only be called after we have passed all sections to Layout.  At
+  // that point we should know what we are discarding.
+  return true;
+}
+
+// Given an address OFFSET relative to the start of input section
+// SHNDX in object OBJECT, return the output offset relative to the
+// start of the section.  This should only be called if SHNDX in
+// OBJECT has a special mapping.
+
+off_t
+Output_section::output_offset(const Relobj* object, unsigned int shndx,
+                             off_t offset) const
+{
+  gold_assert(object->is_section_specially_mapped(shndx));
+  // This can only be called meaningfully when layout is complete.
+  gold_assert(Output_data::is_layout_complete());
+
+  for (Input_section_list::const_iterator p = this->input_sections_.begin();
+       p != this->input_sections_.end();
+       ++p)
+    {
+      off_t output_offset;
+      if (p->output_offset(object, shndx, offset, &output_offset))
+       return output_offset;
+    }
+  gold_unreachable();
+}
+
 // Return the output virtual address of OFFSET relative to the start
 // of input section SHNDX in object OBJECT.
 
@@ -1026,15 +1259,23 @@ uint64_t
 Output_section::output_address(const Relobj* object, unsigned int shndx,
                               off_t offset) const
 {
+  gold_assert(object->is_section_specially_mapped(shndx));
+  // This can only be called meaningfully when layout is complete.
+  gold_assert(Output_data::is_layout_complete());
+
   uint64_t addr = this->address() + this->first_input_offset_;
   for (Input_section_list::const_iterator p = this->input_sections_.begin();
        p != this->input_sections_.end();
        ++p)
     {
       addr = align_address(addr, p->addralign());
-      uint64_t output;
-      if (p->output_address(object, shndx, offset, addr, &output))
-       return output;
+      off_t output_offset;
+      if (p->output_offset(object, shndx, offset, &output_offset))
+       {
+         if (output_offset == -1)
+           return -1U;
+         return addr + output_offset;
+       }
       addr += p->data_size();
     }
 
@@ -1105,6 +1346,16 @@ Output_section::write_header(const Layout* layout,
 void
 Output_section::do_write(Output_file* of)
 {
+  off_t output_section_file_offset = this->offset();
+  for (Fill_list::iterator p = this->fills_.begin();
+       p != this->fills_.end();
+       ++p)
+    {
+      std::string fill_data(of->target()->code_fill(p->length()));
+      of->write(output_section_file_offset + p->section_offset(),
+                fill_data.data(), fill_data.size());
+    }
+
   for (Input_section_list::iterator p = this->input_sections_.begin();
        p != this->input_sections_.end();
        ++p)
@@ -1496,8 +1747,9 @@ Output_segment::write_section_headers_list(const Layout* layout,
 
 // Output_file methods.
 
-Output_file::Output_file(const General_options& options)
+Output_file::Output_file(const General_options& options, Target* target)
   : options_(options),
+    target_(target),
     name_(options.output_file_name()),
     o_(-1),
     file_size_(0),
@@ -1512,40 +1764,41 @@ Output_file::open(off_t file_size)
 {
   this->file_size_ = file_size;
 
-  int mode = this->options_.is_relocatable() ? 0666 : 0777;
+  // Unlink the file first; otherwise the open() may fail if the file
+  // is busy (e.g. it's an executable that's currently being executed).
+  //
+  // However, the linker may be part of a system where a zero-length
+  // file is created for it to write to, with tight permissions (gcc
+  // 2.95 did something like this).  Unlinking the file would work
+  // around those permission controls, so we only unlink if the file
+  // has a non-zero size.  We also unlink only regular files to avoid
+  // trouble with directories/etc.
+  //
+  // If we fail, continue; this command is merely a best-effort attempt
+  // to improve the odds for open().
+
+  struct stat s;
+  if (::stat(this->name_, &s) == 0 && s.st_size != 0)
+    unlink_if_ordinary(this->name_);
+
+  int mode = parameters->output_is_object() ? 0666 : 0777;
   int o = ::open(this->name_, O_RDWR | O_CREAT | O_TRUNC, mode);
   if (o < 0)
-    {
-      fprintf(stderr, _("%s: %s: open: %s\n"),
-             program_name, this->name_, strerror(errno));
-      gold_exit(false);
-    }
+    gold_fatal(_("%s: open: %s"), this->name_, strerror(errno));
   this->o_ = o;
 
   // Write out one byte to make the file the right size.
   if (::lseek(o, file_size - 1, SEEK_SET) < 0)
-    {
-      fprintf(stderr, _("%s: %s: lseek: %s\n"),
-             program_name, this->name_, strerror(errno));
-      gold_exit(false);
-    }
+    gold_fatal(_("%s: lseek: %s"), this->name_, strerror(errno));
   char b = 0;
   if (::write(o, &b, 1) != 1)
-    {
-      fprintf(stderr, _("%s: %s: write: %s\n"),
-             program_name, this->name_, strerror(errno));
-      gold_exit(false);
-    }
+    gold_fatal(_("%s: write: %s"), this->name_, strerror(errno));
 
   // Map the file into memory.
   void* base = ::mmap(NULL, file_size, PROT_READ | PROT_WRITE,
                      MAP_SHARED, o, 0);
   if (base == MAP_FAILED)
-    {
-      fprintf(stderr, _("%s: %s: mmap: %s\n"),
-             program_name, this->name_, strerror(errno));
-      gold_exit(false);
-    }
+    gold_fatal(_("%s: mmap: %s"), this->name_, strerror(errno));
   this->base_ = static_cast<unsigned char*>(base);
 }
 
@@ -1555,116 +1808,159 @@ void
 Output_file::close()
 {
   if (::munmap(this->base_, this->file_size_) < 0)
-    {
-      fprintf(stderr, _("%s: %s: munmap: %s\n"),
-             program_name, this->name_, strerror(errno));
-      gold_exit(false);
-    }
+    gold_error(_("%s: munmap: %s"), this->name_, strerror(errno));
   this->base_ = NULL;
 
   if (::close(this->o_) < 0)
-    {
-      fprintf(stderr, _("%s: %s: close: %s\n"),
-             program_name, this->name_, strerror(errno));
-      gold_exit(false);
-    }
+    gold_error(_("%s: close: %s"), this->name_, strerror(errno));
   this->o_ = -1;
 }
 
 // Instantiate the templates we need.  We could use the configure
 // script to restrict this to only the ones for implemented targets.
 
+#ifdef HAVE_TARGET_32_LITTLE
 template
 off_t
 Output_section::add_input_section<32, false>(
-    Relobj* object,
+    Sized_relobj<32, false>* object,
     unsigned int shndx,
     const char* secname,
-    const elfcpp::Shdr<32, false>& shdr);
+    const elfcpp::Shdr<32, false>& shdr,
+    unsigned int reloc_shndx);
+#endif
 
+#ifdef HAVE_TARGET_32_BIG
 template
 off_t
 Output_section::add_input_section<32, true>(
-    Relobj* object,
+    Sized_relobj<32, true>* object,
     unsigned int shndx,
     const char* secname,
-    const elfcpp::Shdr<32, true>& shdr);
+    const elfcpp::Shdr<32, true>& shdr,
+    unsigned int reloc_shndx);
+#endif
 
+#ifdef HAVE_TARGET_64_LITTLE
 template
 off_t
 Output_section::add_input_section<64, false>(
-    Relobj* object,
+    Sized_relobj<64, false>* object,
     unsigned int shndx,
     const char* secname,
-    const elfcpp::Shdr<64, false>& shdr);
+    const elfcpp::Shdr<64, false>& shdr,
+    unsigned int reloc_shndx);
+#endif
 
+#ifdef HAVE_TARGET_64_BIG
 template
 off_t
 Output_section::add_input_section<64, true>(
-    Relobj* object,
+    Sized_relobj<64, true>* object,
     unsigned int shndx,
     const char* secname,
-    const elfcpp::Shdr<64, true>& shdr);
+    const elfcpp::Shdr<64, true>& shdr,
+    unsigned int reloc_shndx);
+#endif
 
+#ifdef HAVE_TARGET_32_LITTLE
 template
 class Output_data_reloc<elfcpp::SHT_REL, false, 32, false>;
+#endif
 
+#ifdef HAVE_TARGET_32_BIG
 template
 class Output_data_reloc<elfcpp::SHT_REL, false, 32, true>;
+#endif
 
+#ifdef HAVE_TARGET_64_LITTLE
 template
 class Output_data_reloc<elfcpp::SHT_REL, false, 64, false>;
+#endif
 
+#ifdef HAVE_TARGET_64_BIG
 template
 class Output_data_reloc<elfcpp::SHT_REL, false, 64, true>;
+#endif
 
+#ifdef HAVE_TARGET_32_LITTLE
 template
 class Output_data_reloc<elfcpp::SHT_REL, true, 32, false>;
+#endif
 
+#ifdef HAVE_TARGET_32_BIG
 template
 class Output_data_reloc<elfcpp::SHT_REL, true, 32, true>;
+#endif
 
+#ifdef HAVE_TARGET_64_LITTLE
 template
 class Output_data_reloc<elfcpp::SHT_REL, true, 64, false>;
+#endif
 
+#ifdef HAVE_TARGET_64_BIG
 template
 class Output_data_reloc<elfcpp::SHT_REL, true, 64, true>;
+#endif
 
+#ifdef HAVE_TARGET_32_LITTLE
 template
 class Output_data_reloc<elfcpp::SHT_RELA, false, 32, false>;
+#endif
 
+#ifdef HAVE_TARGET_32_BIG
 template
 class Output_data_reloc<elfcpp::SHT_RELA, false, 32, true>;
+#endif
 
+#ifdef HAVE_TARGET_64_LITTLE
 template
 class Output_data_reloc<elfcpp::SHT_RELA, false, 64, false>;
+#endif
 
+#ifdef HAVE_TARGET_64_BIG
 template
 class Output_data_reloc<elfcpp::SHT_RELA, false, 64, true>;
+#endif
 
+#ifdef HAVE_TARGET_32_LITTLE
 template
 class Output_data_reloc<elfcpp::SHT_RELA, true, 32, false>;
+#endif
 
+#ifdef HAVE_TARGET_32_BIG
 template
 class Output_data_reloc<elfcpp::SHT_RELA, true, 32, true>;
+#endif
 
+#ifdef HAVE_TARGET_64_LITTLE
 template
 class Output_data_reloc<elfcpp::SHT_RELA, true, 64, false>;
+#endif
 
+#ifdef HAVE_TARGET_64_BIG
 template
 class Output_data_reloc<elfcpp::SHT_RELA, true, 64, true>;
+#endif
 
+#ifdef HAVE_TARGET_32_LITTLE
 template
 class Output_data_got<32, false>;
+#endif
 
+#ifdef HAVE_TARGET_32_BIG
 template
 class Output_data_got<32, true>;
+#endif
 
+#ifdef HAVE_TARGET_64_LITTLE
 template
 class Output_data_got<64, false>;
+#endif
 
+#ifdef HAVE_TARGET_64_BIG
 template
 class Output_data_got<64, true>;
+#endif
 
 } // End namespace gold.
-
This page took 0.036948 seconds and 4 git commands to generate.