* output.cc (Output_file::open_for_modification): New method.
[binutils-gdb.git] / gold / output.h
index dceaceb7949eb74e3a9eedbdf91f5923de556486..7bd0cf31bba327593b27bdce3610ffb310e1d766 100644 (file)
@@ -1,6 +1,6 @@
 // output.h -- manage the output file for gold   -*- C++ -*-
 
-// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
 // Written by Ian Lance Taylor <iant@google.com>.
 
 // This file is part of gold.
@@ -330,6 +330,13 @@ class Output_data
 
   // Functions that child classes may call.
 
+  // Reset the address.  The Output_section class needs this when an
+  // SHF_ALLOC input section is added to an output section which was
+  // formerly not SHF_ALLOC.
+  void
+  mark_address_invalid()
+  { this->is_address_valid_ = false; }
+
   // Set the size of the data.
   void
   set_data_size(off_t data_size)
@@ -874,6 +881,8 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
   typedef typename elfcpp::Elf_types<size>::Elf_Addr Address;
   typedef typename elfcpp::Elf_types<size>::Elf_Addr Addend;
 
+  static const Address invalid_address = static_cast<Address>(0) - 1;
+
   // An uninitialized entry.  We need this because we want to put
   // instances of this class into an STL container.
   Output_reloc()
@@ -890,7 +899,8 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
   Output_reloc(Symbol* gsym, unsigned int type, Output_data* od,
               Address address, bool is_relative);
 
-  Output_reloc(Symbol* gsym, unsigned int type, Relobj* relobj,
+  Output_reloc(Symbol* gsym, unsigned int type,
+               Sized_relobj<size, big_endian>* relobj,
               unsigned int shndx, Address address, bool is_relative);
 
   // A reloc against a local symbol or local section symbol.
@@ -910,7 +920,8 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
   Output_reloc(Output_section* os, unsigned int type, Output_data* od,
               Address address);
 
-  Output_reloc(Output_section* os, unsigned int type, Relobj* relobj,
+  Output_reloc(Output_section* os, unsigned int type,
+               Sized_relobj<size, big_endian>* relobj,
               unsigned int shndx, Address address);
 
   // Return TRUE if this is a RELATIVE relocation.
@@ -931,7 +942,7 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
   // For a local section symbol, return the offset of the input
   // section within the output section.  ADDEND is the addend being
   // applied to the input section.
-  section_offset_type
+  Address
   local_section_offset(Addend addend) const;
 
   // Get the value of the symbol referred to by a Rel relocation when
@@ -1004,7 +1015,7 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
   {
     // If this->shndx_ is not INVALID CODE, the object which holds the
     // input section being used to specify the reloc address.
-    Relobj* relobj;
+    Sized_relobj<size, big_endian>* relobj;
     // If this->shndx_ is INVALID_CODE, the output data being used to
     // specify the reloc address.  This may be NULL if the reloc
     // address is absolute.
@@ -1053,7 +1064,8 @@ class Output_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
     : rel_(gsym, type, od, address, is_relative), addend_(addend)
   { }
 
-  Output_reloc(Symbol* gsym, unsigned int type, Relobj* relobj,
+  Output_reloc(Symbol* gsym, unsigned int type,
+               Sized_relobj<size, big_endian>* relobj,
               unsigned int shndx, Address address, Addend addend,
               bool is_relative)
     : rel_(gsym, type, relobj, shndx, address, is_relative), addend_(addend)
@@ -1086,7 +1098,8 @@ class Output_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
     : rel_(os, type, od, address), addend_(addend)
   { }
 
-  Output_reloc(Output_section* os, unsigned int type, Relobj* relobj,
+  Output_reloc(Output_section* os, unsigned int type,
+               Sized_relobj<size, big_endian>* relobj,
               unsigned int shndx, Address address, Addend addend)
     : rel_(os, type, relobj, shndx, address), addend_(addend)
   { }
@@ -1215,7 +1228,8 @@ class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
   { this->add(od, Output_reloc_type(gsym, type, od, address, false)); }
 
   void
-  add_global(Symbol* gsym, unsigned int type, Output_data* od, Relobj* relobj,
+  add_global(Symbol* gsym, unsigned int type, Output_data* od,
+             Sized_relobj<size, big_endian>* relobj,
             unsigned int shndx, Address address)
   { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
                                     false)); }
@@ -1231,7 +1245,8 @@ class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
   }
 
   void
-  add_global(Symbol* gsym, unsigned int type, Output_data* od, Relobj* relobj,
+  add_global(Symbol* gsym, unsigned int type, Output_data* od,
+             Sized_relobj<size, big_endian>* relobj,
             unsigned int shndx, Address address, Address addend)
   {
     gold_assert(addend == 0);
@@ -1248,7 +1263,8 @@ class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
 
   void
   add_global_relative(Symbol* gsym, unsigned int type, Output_data* od,
-                      Relobj* relobj, unsigned int shndx, Address address)
+                      Sized_relobj<size, big_endian>* relobj,
+                      unsigned int shndx, Address address)
   {
     this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
                                     true));
@@ -1327,7 +1343,8 @@ class Output_data_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
 
   void
   add_output_section(Output_section* os, unsigned int type, Output_data* od,
-                    Relobj* relobj, unsigned int shndx, Address address)
+                    Sized_relobj<size, big_endian>* relobj,
+                     unsigned int shndx, Address address)
   { this->add(od, Output_reloc_type(os, type, relobj, shndx, address)); }
 };
 
@@ -1359,7 +1376,8 @@ class Output_data_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
                                     false)); }
 
   void
-  add_global(Symbol* gsym, unsigned int type, Output_data* od, Relobj* relobj,
+  add_global(Symbol* gsym, unsigned int type, Output_data* od,
+             Sized_relobj<size, big_endian>* relobj,
             unsigned int shndx, Address address,
             Addend addend)
   { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
@@ -1377,8 +1395,8 @@ class Output_data_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
 
   void
   add_global_relative(Symbol* gsym, unsigned int type, Output_data* od,
-                      Relobj* relobj, unsigned int shndx, Address address,
-                     Addend addend)
+                      Sized_relobj<size, big_endian>* relobj,
+                      unsigned int shndx, Address address, Addend addend)
   { this->add(od, Output_reloc_type(gsym, type, relobj, shndx, address,
                                     addend, true)); }
 
@@ -1455,7 +1473,8 @@ class Output_data_reloc<elfcpp::SHT_RELA, dynamic, size, big_endian>
   { this->add(os, Output_reloc_type(os, type, od, address, addend)); }
 
   void
-  add_output_section(Output_section* os, unsigned int type, Relobj* relobj,
+  add_output_section(Output_section* os, unsigned int type,
+                     Sized_relobj<size, big_endian>* relobj,
                     unsigned int shndx, Address address, Addend addend)
   { this->add(os, Output_reloc_type(os, type, relobj, shndx, address,
                                     addend)); }
@@ -1905,7 +1924,7 @@ class Output_section : public Output_data
 
   // Add a new input section SHNDX, named NAME, with header SHDR, from
   // object OBJECT.  RELOC_SHNDX is the index of a relocation section
-  // which applies to this section, or 0 if none, or -1U if more than
+  // which applies to this section, or 0 if none, or -1 if more than
   // one.  HAVE_SECTIONS_SCRIPT is true if we have a SECTIONS clause
   // in a linker script; in that case we need to keep track of input
   // sections associated with an output section.  Return the offset
@@ -1936,22 +1955,9 @@ class Output_section : public Output_data
   flags() const
   { return this->flags_; }
 
-  // Set the section flags.  This may only be used with the Layout
-  // code when it is prepared to move the section to a different
-  // segment.
-  void
-  set_flags(elfcpp::Elf_Xword flags)
-  { this->flags_ = flags; }
-
   // Update the output section flags based on input section flags.
   void
-  update_flags_for_input_section(elfcpp::Elf_Xword flags)
-  {
-    this->flags_ |= (flags
-                    & (elfcpp::SHF_WRITE
-                       | elfcpp::SHF_ALLOC
-                       | elfcpp::SHF_EXECINSTR));
-  }
+  update_flags_for_input_section(elfcpp::Elf_Xword flags);
 
   // Return the entsize field.
   uint64_t
@@ -2167,6 +2173,11 @@ class Output_section : public Output_data
   set_is_relro()
   { this->is_relro_ = true; }
 
+  // Record that this section does not hold relro data.
+  void
+  clear_is_relro()
+  { this->is_relro_ = false; }
+
   // True if this section holds relro local data--relro data for which
   // the dynamic relocations are all RELATIVE relocations.
   bool
@@ -2178,6 +2189,33 @@ class Output_section : public Output_data
   set_is_relro_local()
   { this->is_relro_local_ = true; }
 
+  // True if this is a small section: a section which holds small
+  // variables.
+  bool
+  is_small_section() const
+  { return this->is_small_section_; }
+
+  // Record that this is a small section.
+  void
+  set_is_small_section()
+  { this->is_small_section_ = true; }
+
+  // True if this is a large section: a section which holds large
+  // variables.
+  bool
+  is_large_section() const
+  { return this->is_large_section_; }
+
+  // Record that this is a large section.
+  void
+  set_is_large_section()
+  { this->is_large_section_ = true; }
+
+  // True if this is a large data (not BSS) section.
+  bool
+  is_large_data_section()
+  { return this->is_large_section_ && this->type_ != elfcpp::SHT_NOBITS; }
+
   // Return whether this section should be written after all the input
   // sections are complete.
   bool
@@ -2243,12 +2281,14 @@ class Output_section : public Output_data
   output_address(const Relobj* object, unsigned int shndx,
                 off_t offset) const;
 
-  // Return the output address of the start of the merged section for
-  // input section SHNDX in object OBJECT.  This is not necessarily
-  // the offset corresponding to input offset 0 in the section, since
-  // the section may be mapped arbitrarily.
-  uint64_t
-  starting_output_address(const Relobj* object, unsigned int shndx) const;
+  // Look for the merged section for input section SHNDX in object
+  // OBJECT.  If found, return true, and set *ADDR to the address of
+  // the start of the merged section.  This is not necessary the
+  // output offset corresponding to input offset 0 in the section,
+  // since the section may be mapped arbitrarily.
+  bool
+  find_starting_output_address(const Relobj* object, unsigned int shndx,
+                              uint64_t* addr) const;
 
   // Record that this output section was found in the SECTIONS clause
   // of a linker script.
@@ -2443,8 +2483,7 @@ class Output_section : public Output_data
 
     // For a non-merge output section.
     Input_section(Output_section_data* posd)
-      : shndx_(OUTPUT_SECTION_CODE),
-       p2align_(ffsll(static_cast<long long>(posd->addralign())))
+      : shndx_(OUTPUT_SECTION_CODE), p2align_(0)
     {
       this->u1_.data_size = 0;
       this->u2_.posd = posd;
@@ -2455,7 +2494,7 @@ class Output_section : public Output_data
       : shndx_(is_string
               ? MERGE_STRING_SECTION_CODE
               : MERGE_DATA_SECTION_CODE),
-       p2align_(ffsll(static_cast<long long>(posd->addralign())))
+       p2align_(0)
     {
       this->u1_.entsize = entsize;
       this->u2_.posd = posd;
@@ -2465,6 +2504,8 @@ class Output_section : public Output_data
     uint64_t
     addralign() const
     {
+      if (!this->is_input_section())
+       return this->u2_.posd->addralign();
       return (this->p2align_ == 0
              ? 0
              : static_cast<uint64_t>(1) << (this->p2align_ - 1));
@@ -2788,6 +2829,10 @@ class Output_section : public Output_data
   bool is_relro_ : 1;
   // True if this section holds relro local data.
   bool is_relro_local_ : 1;
+  // True if this is a small section.
+  bool is_small_section_ : 1;
+  // True if this is a large section.
+  bool is_large_section_ : 1;
   // For SHT_TLS sections, the offset of this section relative to the base
   // of the TLS segment.
   uint64_t tls_offset_;
@@ -2838,6 +2883,17 @@ class Output_segment
   offset() const
   { return this->offset_; }
 
+  // Whether this is a segment created to hold large data sections.
+  bool
+  is_large_data_segment() const
+  { return this->is_large_data_segment_; }
+
+  // Record that this is a segment created to hold large data
+  // sections.
+  void
+  set_is_large_data_segment()
+  { this->is_large_data_segment_ = true; }
+
   // Return the maximum alignment of the Output_data.
   uint64_t
   maximum_alignment();
@@ -3020,6 +3076,8 @@ class Output_segment
   bool is_max_align_known_ : 1;
   // Whether vaddr and paddr were set by a linker script.
   bool are_addresses_set_ : 1;
+  // Whether this segment holds large data sections.
+  bool is_large_data_segment_ : 1;
 };
 
 // This class represents the output file.
@@ -3035,16 +3093,24 @@ class Output_file
   set_is_temporary()
   { this->is_temporary_ = true; }
 
+  // Try to open an existing file. Returns false if the file doesn't
+  // exist, has a size of 0 or can't be mmaped.  This method is
+  // thread-unsafe.
+  bool
+  open_for_modification();
+
   // Open the output file.  FILE_SIZE is the final size of the file.
+  // If the file already exists, it is deleted/truncated.  This method
+  // is thread-unsafe.
   void
   open(off_t file_size);
 
-  // Resize the output file.
+  // Resize the output file.  This method is thread-unsafe.
   void
   resize(off_t file_size);
 
   // Close the output file (flushing all buffered data) and make sure
-  // there are no errors.
+  // there are no errors.  This method is thread-unsafe.
   void
   close();
 
@@ -3095,10 +3161,19 @@ class Output_file
   { }
 
  private:
-  // Map the file into memory and return a pointer to the map.
+  // Map the file into memory or, if that fails, allocate anonymous
+  // memory.
   void
   map();
 
+  // Allocate anonymous memory for the file.
+  bool
+  map_anonymous();
+
+  // Map the file into memory.
+  bool
+  map_no_anonymous();
+
   // Unmap the file from memory (and flush to disk buffers).
   void
   unmap();