Implement SIZEOF_HEADERS, section constraints, other minor linker
authorIan Lance Taylor <iant@google.com>
Mon, 4 Feb 2008 06:45:50 +0000 (06:45 +0000)
committerIan Lance Taylor <iant@google.com>
Mon, 4 Feb 2008 06:45:50 +0000 (06:45 +0000)
script items.

gold/expression.cc
gold/layout.cc
gold/layout.h
gold/output.cc
gold/script-c.h
gold/script-sections.cc
gold/script-sections.h
gold/script.cc
gold/yyscript.y

index e8fd9fd8954477e934bf5ee3599bce17808a98fe..d57b45cb396fddf76b8dc5f67d6fe84c9b09de69 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <string>
 
+#include "elfcpp.h"
 #include "parameters.h"
 #include "symtab.h"
 #include "layout.h"
@@ -632,78 +633,197 @@ script_exp_function_addr(const char* section_name, size_t section_name_len)
   return new Addr_expression(section_name, section_name_len);
 }
 
-// Functions.
+// CONSTANT.  It would be nice if we could simply evaluate this
+// immediately and return an Integer_expression, but unfortunately we
+// don't know the target.
+
+class Constant_expression : public Expression
+{
+ public:
+  Constant_expression(const char* name, size_t length);
+
+  uint64_t
+  value(const Expression_eval_info*);
+
+  void
+  print(FILE* f) const;
+
+ private:
+  enum Constant_function
+  {
+    CONSTANT_MAXPAGESIZE,
+    CONSTANT_COMMONPAGESIZE
+  };
 
+  Constant_function function_;
+};
+
+Constant_expression::Constant_expression(const char* name, size_t length)
+{
+  if (length == 11 && strncmp(name, "MAXPAGESIZE", length) == 0)
+    this->function_ = CONSTANT_MAXPAGESIZE;
+  else if (length == 14 && strncmp(name, "COMMONPAGESIZE", length) == 0)
+    this->function_ = CONSTANT_COMMONPAGESIZE;
+  else
+    {
+      std::string s(name, length);
+      gold_error(_("unknown constant %s"), s.c_str());
+      this->function_ = CONSTANT_MAXPAGESIZE;
+    }
+}
+
+uint64_t
+Constant_expression::value(const Expression_eval_info*)
+{
+  switch (this->function_)
+    {
+    case CONSTANT_MAXPAGESIZE:
+      return parameters->target()->abi_pagesize();
+    case CONSTANT_COMMONPAGESIZE:
+      return parameters->target()->common_pagesize();
+    default:
+      gold_unreachable();
+    }
+}
+
+void
+Constant_expression::print(FILE* f) const
+{
+  const char* name;
+  switch (this->function_)
+    {
+    case CONSTANT_MAXPAGESIZE:
+      name = "MAXPAGESIZE";
+      break;
+    case CONSTANT_COMMONPAGESIZE:
+      name = "COMMONPAGESIZE";
+      break;
+    default:
+      gold_unreachable();
+    }
+  fprintf(f, "CONSTANT(%s)", name);
+}
+  
 extern "C" Expression*
-script_exp_function_defined(const char*, size_t)
+script_exp_function_constant(const char* name, size_t length)
 {
-  gold_fatal(_("DEFINED not implemented"));
+  return new Constant_expression(name, length);
 }
 
+// DATA_SEGMENT_ALIGN.  FIXME: we don't implement this; we always fall
+// back to the general case.
+
 extern "C" Expression*
-script_exp_function_sizeof_headers()
+script_exp_function_data_segment_align(Expression* left, Expression*)
 {
-  gold_fatal(_("SIZEOF_HEADERS not implemented"));
+  Expression* e1 = script_exp_function_align(script_exp_string(".", 1), left);
+  Expression* e2 = script_exp_binary_sub(left, script_exp_integer(1));
+  Expression* e3 = script_exp_binary_bitwise_and(script_exp_string(".", 1),
+                                                e2);
+  return script_exp_binary_add(e1, e3);
 }
 
+// DATA_SEGMENT_RELRO.  FIXME: This is not implemented.
+
 extern "C" Expression*
-script_exp_function_alignof(const char*, size_t)
+script_exp_function_data_segment_relro_end(Expression*, Expression* right)
 {
-  gold_fatal(_("ALIGNOF not implemented"));
+  return right;
 }
 
+// DATA_SEGMENT_END.  FIXME: This is not implemented.
+
 extern "C" Expression*
-script_exp_function_sizeof(const char*, size_t)
+script_exp_function_data_segment_end(Expression* val)
 {
-  gold_fatal(_("SIZEOF not implemented"));
+  return val;
+}
+
+// SIZEOF_HEADERS.
+
+class Sizeof_headers_expression : public Expression
+{
+ public:
+  Sizeof_headers_expression()
+  { }
+
+  uint64_t
+  value(const Expression_eval_info*);
+
+  void
+  print(FILE* f) const
+  { fprintf(f, "SIZEOF_HEADERS"); }
+};
+
+uint64_t
+Sizeof_headers_expression::value(const Expression_eval_info* eei)
+{
+  unsigned int ehdr_size;
+  unsigned int phdr_size;
+  if (parameters->get_size() == 32)
+    {
+      ehdr_size = elfcpp::Elf_sizes<32>::ehdr_size;
+      phdr_size = elfcpp::Elf_sizes<32>::phdr_size;
+    }
+  else if (parameters->get_size() == 64)
+    {
+      ehdr_size = elfcpp::Elf_sizes<64>::ehdr_size;
+      phdr_size = elfcpp::Elf_sizes<64>::phdr_size;
+    }
+  else
+    gold_unreachable();
+
+  return ehdr_size + phdr_size * eei->layout->expected_segment_count();
 }
 
 extern "C" Expression*
-script_exp_function_loadaddr(const char*, size_t)
+script_exp_function_sizeof_headers()
 {
-  gold_fatal(_("LOADADDR not implemented"));
+  return new Sizeof_headers_expression();
 }
 
+// Functions.
+
 extern "C" Expression*
-script_exp_function_origin(const char*, size_t)
+script_exp_function_defined(const char*, size_t)
 {
-  gold_fatal(_("ORIGIN not implemented"));
+  gold_fatal(_("DEFINED not implemented"));
 }
 
 extern "C" Expression*
-script_exp_function_length(const char*, size_t)
+script_exp_function_alignof(const char*, size_t)
 {
-  gold_fatal(_("LENGTH not implemented"));
+  gold_fatal(_("ALIGNOF not implemented"));
 }
 
 extern "C" Expression*
-script_exp_function_constant(const char*, size_t)
+script_exp_function_sizeof(const char*, size_t)
 {
-  gold_fatal(_("CONSTANT not implemented"));
+  gold_fatal(_("SIZEOF not implemented"));
 }
 
 extern "C" Expression*
-script_exp_function_absolute(Expression*)
+script_exp_function_loadaddr(const char*, size_t)
 {
-  gold_fatal(_("ABSOLUTE not implemented"));
+  gold_fatal(_("LOADADDR not implemented"));
 }
 
 extern "C" Expression*
-script_exp_function_data_segment_align(Expression*, Expression*)
+script_exp_function_origin(const char*, size_t)
 {
-  gold_fatal(_("DATA_SEGMENT_ALIGN not implemented"));
+  gold_fatal(_("ORIGIN not implemented"));
 }
 
 extern "C" Expression*
-script_exp_function_data_segment_relro_end(Expression*, Expression*)
+script_exp_function_length(const char*, size_t)
 {
-  gold_fatal(_("DATA_SEGMENT_RELRO_END not implemented"));
+  gold_fatal(_("LENGTH not implemented"));
 }
 
 extern "C" Expression*
-script_exp_function_data_segment_end(Expression*)
+script_exp_function_absolute(Expression*)
 {
-  gold_fatal(_("DATA_SEGMENT_END not implemented"));
+  gold_fatal(_("ABSOLUTE not implemented"));
 }
 
 extern "C" Expression*
index a0fcc49d6a7461adafce5b576279e2e41fafa8c8..1e597ac6f251d1155421ad42a2f83603bf8021f7 100644 (file)
@@ -397,9 +397,9 @@ Layout::layout_eh_frame(Sized_relobj<size, big_endian>* object,
 
              hdr_os->set_after_input_sections();
 
-             Output_segment* hdr_oseg =
-               new Output_segment(elfcpp::PT_GNU_EH_FRAME, elfcpp::PF_R);
-             this->segment_list_.push_back(hdr_oseg);
+             Output_segment* hdr_oseg;
+             hdr_oseg = this->make_output_segment(elfcpp::PT_GNU_EH_FRAME,
+                                                  elfcpp::PF_R);
              hdr_oseg->add_output_section(hdr_os, elfcpp::PF_R);
 
              this->eh_frame_data_->set_eh_frame_hdr(hdr_posd);
@@ -523,9 +523,8 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
 
       if (p == this->segment_list_.end())
        {
-         Output_segment* oseg = new Output_segment(elfcpp::PT_LOAD,
-                                                   seg_flags);
-         this->segment_list_.push_back(oseg);
+         Output_segment* oseg = this->make_output_segment(elfcpp::PT_LOAD,
+                                                          seg_flags);
          oseg->add_output_section(os, seg_flags);
        }
 
@@ -549,9 +548,8 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
 
          if (p == this->segment_list_.end())
            {
-             Output_segment* oseg = new Output_segment(elfcpp::PT_NOTE,
-                                                       seg_flags);
-             this->segment_list_.push_back(oseg);
+             Output_segment* oseg = this->make_output_segment(elfcpp::PT_NOTE,
+                                                              seg_flags);
              oseg->add_output_section(os, seg_flags);
            }
        }
@@ -561,11 +559,8 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
       if ((flags & elfcpp::SHF_TLS) != 0)
        {
          if (this->tls_segment_ == NULL)
-           {
-             this->tls_segment_ = new Output_segment(elfcpp::PT_TLS,
-                                                     seg_flags);
-             this->segment_list_.push_back(this->tls_segment_);
-           }
+           this->tls_segment_ = this->make_output_segment(elfcpp::PT_TLS,
+                                                          seg_flags);
          this->tls_segment_->add_output_section(os, seg_flags);
        }
     }
@@ -573,6 +568,27 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
   return os;
 }
 
+// Return the number of segments we expect to see.
+
+size_t
+Layout::expected_segment_count() const
+{
+  size_t ret = this->segment_list_.size();
+
+  // If we didn't see a SECTIONS clause in a linker script, we should
+  // already have the complete list of segments.  Otherwise we ask the
+  // SECTIONS clause how many segments it expects, and add in the ones
+  // we already have (PT_GNU_STACK, PT_GNU_EH_FRAME, etc.)
+
+  if (!this->script_options_->saw_sections_clause())
+    return ret;
+  else
+    {
+      const Script_sections* ss = this->script_options_->script_sections();
+      return ret + ss->expected_segment_count(this);
+    }
+}
+
 // Handle the .note.GNU-stack section at layout time.  SEEN_GNU_STACK
 // is whether we saw a .note.GNU-stack section in the object file.
 // GNU_STACK_FLAGS is the section flags.  The flags give the
@@ -603,11 +619,11 @@ Layout::create_initial_dynamic_sections(Symbol_table* symtab)
   if (parameters->doing_static_link())
     return;
 
-  const char* dynamic_name = this->namepool_.add(".dynamic", false, NULL);
-  this->dynamic_section_ = this->make_output_section(dynamic_name,
-                                                    elfcpp::SHT_DYNAMIC,
-                                                    (elfcpp::SHF_ALLOC
-                                                     | elfcpp::SHF_WRITE));
+  this->dynamic_section_ = this->choose_output_section(NULL, ".dynamic",
+                                                      elfcpp::SHT_DYNAMIC,
+                                                      (elfcpp::SHF_ALLOC
+                                                       | elfcpp::SHF_WRITE),
+                                                      false);
 
   symtab->define_in_output_data("_DYNAMIC", NULL, this->dynamic_section_, 0, 0,
                                elfcpp::STT_OBJECT, elfcpp::STB_LOCAL,
@@ -684,8 +700,8 @@ Layout::find_first_load_seg()
        return *p;
     }
 
-  Output_segment* load_seg = new Output_segment(elfcpp::PT_LOAD, elfcpp::PF_R);
-  this->segment_list_.push_back(load_seg);
+  Output_segment* load_seg = this->make_output_segment(elfcpp::PT_LOAD,
+                                                      elfcpp::PF_R);
   return load_seg;
 }
 
@@ -734,11 +750,16 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab,
   this->create_gold_note();
   this->create_executable_stack_info(target);
 
+  Output_segment* phdr_seg = NULL;
   if (!parameters->output_is_object() && !parameters->doing_static_link())
     {
       // There was a dynamic object in the link.  We need to create
       // some information for the dynamic linker.
 
+      // Create the PT_PHDR segment which will hold the program
+      // headers.
+      phdr_seg = this->make_output_segment(elfcpp::PT_PHDR, elfcpp::PF_R);
+
       // Create the dynamic symbol table, including the hash table.
       Output_section* dynstr;
       std::vector<Symbol*> dynamic_symbols;
@@ -775,16 +796,7 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab,
   else
     load_seg = this->find_first_load_seg();
 
-  Output_segment* phdr_seg = NULL;
-  if (load_seg != NULL
-      && !parameters->output_is_object()
-      && !parameters->doing_static_link())
-    {
-      // Create the PT_PHDR segment which will hold the program
-      // headers.
-      phdr_seg = new Output_segment(elfcpp::PT_PHDR, elfcpp::PF_R);
-      this->segment_list_.push_back(phdr_seg);
-    }
+  gold_assert(phdr_seg == NULL || load_seg != NULL);
 
   // Lay out the segment headers.
   Output_segment_headers* segment_headers;
@@ -988,8 +1000,7 @@ Layout::create_executable_stack_info(const Target* target)
       int flags = elfcpp::PF_R | elfcpp::PF_W;
       if (is_stack_executable)
        flags |= elfcpp::PF_X;
-      Output_segment* oseg = new Output_segment(elfcpp::PT_GNU_STACK, flags);
-      this->segment_list_.push_back(oseg);
+      this->make_output_segment(elfcpp::PT_GNU_STACK, flags);
     }
 }
 
@@ -1591,10 +1602,10 @@ Layout::create_dynamic_symtab(const Input_objects* input_objects,
 
   // Create the dynamic symbol table section.
 
-  const char* dynsym_name = this->namepool_.add(".dynsym", false, NULL);
-  Output_section* dynsym = this->make_output_section(dynsym_name,
-                                                    elfcpp::SHT_DYNSYM,
-                                                    elfcpp::SHF_ALLOC);
+  Output_section* dynsym = this->choose_output_section(NULL, ".dynsym",
+                                                      elfcpp::SHT_DYNSYM,
+                                                      elfcpp::SHF_ALLOC,
+                                                      false);
 
   Output_section_data* odata = new Output_data_fixed_space(index * symsize,
                                                           align);
@@ -1612,10 +1623,10 @@ Layout::create_dynamic_symtab(const Input_objects* input_objects,
 
   // Create the dynamic string table section.
 
-  const char* dynstr_name = this->namepool_.add(".dynstr", false, NULL);
-  Output_section* dynstr = this->make_output_section(dynstr_name,
-                                                    elfcpp::SHT_STRTAB,
-                                                    elfcpp::SHF_ALLOC);
+  Output_section* dynstr = this->choose_output_section(NULL, ".dynstr",
+                                                      elfcpp::SHT_STRTAB,
+                                                      elfcpp::SHF_ALLOC,
+                                                      false);
 
   Output_section_data* strdata = new Output_data_strtab(&this->dynpool_);
   dynstr->add_output_section_data(strdata);
@@ -1637,10 +1648,10 @@ Layout::create_dynamic_symtab(const Input_objects* input_objects,
   Dynobj::create_elf_hash_table(*pdynamic_symbols, local_symcount,
                                &phash, &hashlen);
 
-  const char* hash_name = this->namepool_.add(".hash", false, NULL);
-  Output_section* hashsec = this->make_output_section(hash_name,
-                                                     elfcpp::SHT_HASH,
-                                                     elfcpp::SHF_ALLOC);
+  Output_section* hashsec = this->choose_output_section(NULL, ".hash",
+                                                       elfcpp::SHT_HASH,
+                                                       elfcpp::SHF_ALLOC,
+                                                       false);
 
   Output_section_data* hashdata = new Output_data_const_buffer(phash,
                                                               hashlen,
@@ -1753,10 +1764,10 @@ Layout::sized_create_version_sections(
     const Output_section* dynstr
     ACCEPT_SIZE_ENDIAN)
 {
-  const char* vname = this->namepool_.add(".gnu.version", false, NULL);
-  Output_section* vsec = this->make_output_section(vname,
-                                                  elfcpp::SHT_GNU_versym,
-                                                  elfcpp::SHF_ALLOC);
+  Output_section* vsec = this->choose_output_section(NULL, ".gnu.version",
+                                                    elfcpp::SHT_GNU_versym,
+                                                    elfcpp::SHF_ALLOC,
+                                                    false);
 
   unsigned char* vbuf;
   unsigned int vsize;
@@ -1775,10 +1786,11 @@ Layout::sized_create_version_sections(
 
   if (versions->any_defs())
     {
-      const char* vdname = this->namepool_.add(".gnu.version_d", false, NULL);
-      Output_section *vdsec;
-      vdsec = this->make_output_section(vdname, elfcpp::SHT_GNU_verdef,
-                                       elfcpp::SHF_ALLOC);
+      Output_section* vdsec;
+      vdsec= this->choose_output_section(NULL, ".gnu.version_d",
+                                        elfcpp::SHT_GNU_verdef,
+                                        elfcpp::SHF_ALLOC,
+                                        false);
 
       unsigned char* vdbuf;
       unsigned int vdsize;
@@ -1801,10 +1813,11 @@ Layout::sized_create_version_sections(
 
   if (versions->any_needs())
     {
-      const char* vnname = this->namepool_.add(".gnu.version_r", false, NULL);
       Output_section* vnsec;
-      vnsec = this->make_output_section(vnname, elfcpp::SHT_GNU_verneed,
-                                       elfcpp::SHF_ALLOC);
+      vnsec = this->choose_output_section(NULL, ".gnu.version_r",
+                                         elfcpp::SHT_GNU_verneed,
+                                         elfcpp::SHF_ALLOC,
+                                         false);
 
       unsigned char* vnbuf;
       unsigned int vnsize;
@@ -1842,14 +1855,14 @@ Layout::create_interp(const Target* target)
 
   Output_section_data* odata = new Output_data_const(interp, len, 1);
 
-  const char* interp_name = this->namepool_.add(".interp", false, NULL);
-  Output_section* osec = this->make_output_section(interp_name,
-                                                  elfcpp::SHT_PROGBITS,
-                                                  elfcpp::SHF_ALLOC);
+  Output_section* osec = this->choose_output_section(NULL, ".interp",
+                                                    elfcpp::SHT_PROGBITS,
+                                                    elfcpp::SHF_ALLOC,
+                                                    false);
   osec->add_output_section_data(odata);
 
-  Output_segment* oseg = new Output_segment(elfcpp::PT_INTERP, elfcpp::PF_R);
-  this->segment_list_.push_back(oseg);
+  Output_segment* oseg = this->make_output_segment(elfcpp::PT_INTERP,
+                                                  elfcpp::PF_R);
   oseg->add_initial_output_section(osec, elfcpp::PF_R);
 }
 
@@ -1859,9 +1872,9 @@ void
 Layout::finish_dynamic_section(const Input_objects* input_objects,
                               const Symbol_table* symtab)
 {
-  Output_segment* oseg = new Output_segment(elfcpp::PT_DYNAMIC,
-                                           elfcpp::PF_R | elfcpp::PF_W);
-  this->segment_list_.push_back(oseg);
+  Output_segment* oseg = this->make_output_segment(elfcpp::PT_DYNAMIC,
+                                                  (elfcpp::PF_R
+                                                   | elfcpp::PF_W));
   oseg->add_initial_output_section(this->dynamic_section_,
                                   elfcpp::PF_R | elfcpp::PF_W);
 
index ceacf5dd419ee6e6cbbc6f5a8931bb55446dacd0..d7f59650432e928ec0e1cb3a3ada4077a5d46d17 100644 (file)
@@ -237,6 +237,10 @@ class Layout
   find_output_segment(elfcpp::PT type, elfcpp::Elf_Word set,
                      elfcpp::Elf_Word clear) const;
 
+  // Return the number of segments we expect to produce.
+  size_t
+  expected_segment_count() const;
+
   // Set a flag to indicate that an object file uses the static TLS model.
   void
   set_has_static_tls()
index c0db1afdc2f12a7397705b9b34f72ce8dfa0f931..8eb79fa9e1a7821c8d1d2450c6f363c5a9e631e4 100644 (file)
@@ -2324,21 +2324,22 @@ Output_segment::set_section_list_addresses(bool reset, Output_data_list* pdl,
        p != pdl->end();
        ++p)
     {
-      off = align_address(off, (*p)->addralign());
-
       if (reset)
        (*p)->reset_address_and_file_offset();
 
       // When using a linker script the section will most likely
       // already have an address.
       if (!(*p)->is_address_valid())
-       (*p)->set_address_and_file_offset(addr + (off - startoff), off);
+       {
+         off = align_address(off, (*p)->addralign());
+         (*p)->set_address_and_file_offset(addr + (off - startoff), off);
+       }
       else
        {
          // The script may have inserted a skip forward, but it
          // better not have moved backward.
-         gold_assert((*p)->address() >= addr);
-         off = startoff + ((*p)->address() - addr);
+         gold_assert((*p)->address() >= addr + (off - startoff));
+         off += (*p)->address() - (addr + (off - startoff));
          (*p)->set_file_offset(off);
          (*p)->finalize_data_size();
        }
index 496e18b5f24112c66edc02518d361801f8704f6c..26dc5566042202857a4297e1a60ad189bfca83ae 100644 (file)
@@ -61,6 +61,21 @@ typedef Expression* Expression_ptr;
 typedef void* Expression_ptr;
 #endif
 
+/* A constraint for whether to use a particular output section
+   definition.  */
+
+enum Section_constraint
+{
+  /* No constraint.  */
+  CONSTRAINT_NONE,
+  /* Only if all input sections are read-only.  */
+  CONSTRAINT_ONLY_IF_RO,
+  /* Only if at least input section is writable.  */
+  CONSTRAINT_ONLY_IF_RW,
+  /* Special constraint.  */
+  CONSTRAINT_SPECIAL
+};
+
 /* The information we store for an output section header in the bison
    parser.  */
 
@@ -75,6 +90,8 @@ struct Parser_output_section_header
   /* The input section alignment, from the SUBALIGN specifier.  This
      may be NULL.  */
   Expression_ptr subalign;
+  /* A constraint on this output section.  */
+  enum Section_constraint constraint;
 };
 
 /* The information we store for an output section trailer in the bison
@@ -204,6 +221,11 @@ script_set_entry(void* closure, const char*, size_t);
 extern void
 script_parse_option(void* closure, const char*, size_t);
 
+/* Called by the bison parser to handle SEARCH_DIR.  */
+
+extern void
+script_add_search_dir(void* closure, const char*, size_t);
+
 /* Called by the bison parser to push the lexer into expression
    mode.  */
 
index 2505170fb77c722f585043af92aec065028af928..6c8a7f5b2b34677e7a1ef46fd7e271cbd57df928 100644 (file)
@@ -82,6 +82,20 @@ class Sections_element
   set_section_addresses(Symbol_table*, Layout*, bool*, uint64_t*)
   { }
 
+  // Check a constraint (ONLY_IF_RO, etc.) on an output section.  If
+  // this section is constrained, and the input sections do not match,
+  // return the constraint, and set *POSD.
+  virtual Section_constraint
+  check_constraint(Output_section_definition**)
+  { return CONSTRAINT_NONE; }
+
+  // See if this is the alternate output section for a constrained
+  // output section.  If it is, transfer the Output_section and return
+  // true.  Otherwise return false.
+  virtual bool
+  alternate_constraint(Output_section_definition*, Section_constraint)
+  { return false; }
+
   // Print the element for debugging purposes.
   virtual void
   print(FILE* f) const = 0;
@@ -1146,6 +1160,18 @@ class Output_section_definition : public Sections_element
   set_section_addresses(Symbol_table* symtab, Layout* layout,
                        bool* dot_has_value, uint64_t* dot_value);
 
+  // Check a constraint (ONLY_IF_RO, etc.) on an output section.  If
+  // this section is constrained, and the input sections do not match,
+  // return the constraint, and set *POSD.
+  Section_constraint
+  check_constraint(Output_section_definition** posd);
+
+  // See if this is the alternate output section for a constrained
+  // output section.  If it is, transfer the Output_section and return
+  // true.  Otherwise return false.
+  bool
+  alternate_constraint(Output_section_definition*, Section_constraint);
+
   // Print the contents to the FILE.  This is for debugging.
   void
   print(FILE*) const;
@@ -1163,6 +1189,8 @@ class Output_section_definition : public Sections_element
   Expression* align_;
   // The input section alignment.  This may be NULL.
   Expression* subalign_;
+  // The constraint, if any.
+  Section_constraint constraint_;
   // The fill value.  This may be NULL.
   Expression* fill_;
   // The list of elements defining the section.
@@ -1183,6 +1211,7 @@ Output_section_definition::Output_section_definition(
     load_address_(header->load_address),
     align_(header->align),
     subalign_(header->subalign),
+    constraint_(header->constraint),
     fill_(NULL),
     elements_(),
     output_section_(NULL)
@@ -1540,6 +1569,88 @@ Output_section_definition::set_section_addresses(Symbol_table* symtab,
   gold_assert(input_sections.empty());
 }
 
+// Check a constraint (ONLY_IF_RO, etc.) on an output section.  If
+// this section is constrained, and the input sections do not match,
+// return the constraint, and set *POSD.
+
+Section_constraint
+Output_section_definition::check_constraint(Output_section_definition** posd)
+{
+  switch (this->constraint_)
+    {
+    case CONSTRAINT_NONE:
+      return CONSTRAINT_NONE;
+
+    case CONSTRAINT_ONLY_IF_RO:
+      if (this->output_section_ != NULL
+         && (this->output_section_->flags() & elfcpp::SHF_WRITE) != 0)
+       {
+         *posd = this;
+         return CONSTRAINT_ONLY_IF_RO;
+       }
+      return CONSTRAINT_NONE;
+
+    case CONSTRAINT_ONLY_IF_RW:
+      if (this->output_section_ != NULL
+         && (this->output_section_->flags() & elfcpp::SHF_WRITE) == 0)
+       {
+         *posd = this;
+         return CONSTRAINT_ONLY_IF_RW;
+       }
+      return CONSTRAINT_NONE;
+
+    case CONSTRAINT_SPECIAL:
+      if (this->output_section_ != NULL)
+       gold_error(_("SPECIAL constraints are not implemented"));
+      return CONSTRAINT_NONE;
+
+    default:
+      gold_unreachable();
+    }
+}
+
+// See if this is the alternate output section for a constrained
+// output section.  If it is, transfer the Output_section and return
+// true.  Otherwise return false.
+
+bool
+Output_section_definition::alternate_constraint(
+    Output_section_definition* posd,
+    Section_constraint constraint)
+{
+  if (this->name_ != posd->name_)
+    return false;
+
+  switch (constraint)
+    {
+    case CONSTRAINT_ONLY_IF_RO:
+      if (this->constraint_ != CONSTRAINT_ONLY_IF_RW)
+       return false;
+      break;
+
+    case CONSTRAINT_ONLY_IF_RW:
+      if (this->constraint_ != CONSTRAINT_ONLY_IF_RO)
+       return false;
+      break;
+
+    default:
+      gold_unreachable();
+    }
+
+  // We have found the alternate constraint.  We just need to move
+  // over the Output_section.  When constraints are used properly,
+  // THIS should not have an output_section pointer, as all the input
+  // sections should have matched the other definition.
+
+  if (this->output_section_ != NULL)
+    gold_error(_("mismatched definition for constrained sections"));
+
+  this->output_section_ = posd->output_section_;
+  posd->output_section_ = NULL;
+
+  return true;
+}
+
 // Print for debugging.
 
 void
@@ -1926,6 +2037,33 @@ Script_sections::set_section_addresses(Symbol_table* symtab, Layout* layout)
 {
   gold_assert(this->saw_sections_clause_);
 
+  // Implement ONLY_IF_RO/ONLY_IF_RW constraints.  These are a pain
+  // for our representation.
+  for (Sections_elements::iterator p = this->sections_elements_->begin();
+       p != this->sections_elements_->end();
+       ++p)
+    {
+      Output_section_definition* posd;
+      Section_constraint failed_constraint = (*p)->check_constraint(&posd);
+      if (failed_constraint != CONSTRAINT_NONE)
+       {
+         Sections_elements::iterator q;
+         for (q = this->sections_elements_->begin();
+              q != this->sections_elements_->end();
+              ++q)
+           {
+             if (q != p)
+               {
+                 if ((*q)->alternate_constraint(posd, failed_constraint))
+                   break;
+               }
+           }
+
+         if (q == this->sections_elements_->end())
+           gold_error(_("no matching section constraint"));
+       }
+    }
+
   bool dot_has_value = false;
   uint64_t dot_value = 0;
   for (Sections_elements::iterator p = this->sections_elements_->begin();
@@ -2118,10 +2256,15 @@ Script_sections::create_segments(Layout* layout)
   else
     gold_unreachable();
 
+  size_t sizeof_headers = file_header_size + segment_headers_size;
+
   if (first_seg != NULL
-      && ((first_seg->paddr() & (abi_pagesize - 1))
-         >= file_header_size + segment_headers_size))
-    return first_seg;
+      && (first_seg->paddr() & (abi_pagesize - 1)) >= sizeof_headers)
+    {
+      first_seg->set_addresses(first_seg->vaddr() - sizeof_headers,
+                              first_seg->paddr() - sizeof_headers);
+      return first_seg;
+    }
 
   Output_segment* load_seg = layout->make_output_segment(elfcpp::PT_LOAD,
                                                         elfcpp::PF_R);
@@ -2132,16 +2275,13 @@ Script_sections::create_segments(Layout* layout)
       uint64_t vma = first_seg->vaddr();
       uint64_t lma = first_seg->paddr();
 
-      if (lma >= file_header_size + segment_headers_size
-         && lma >= abi_pagesize)
-       {
-         // We want a segment with the same relationship between VMA
-         // and LMA, but with enough room for the headers.
-         uint64_t size_for_page = align_address((file_header_size
-                                                 + segment_headers_size),
-                                                abi_pagesize);
-         load_seg->set_addresses(vma - size_for_page, lma - size_for_page);
-       }
+      // We want a segment with the same relationship between VMA and
+      // LMA, but with enough room for the headers, and aligned to
+      // load at the start of a page.
+      uint64_t hdr_lma = lma - sizeof_headers;
+      hdr_lma &= ~(abi_pagesize - 1);
+      if (lma >= hdr_lma && vma >= (lma - hdr_lma))
+       load_seg->set_addresses(vma - (lma - hdr_lma), hdr_lma);
       else
        {
          // We could handle this case by create the file header
@@ -2216,6 +2356,48 @@ Script_sections::create_note_and_tls_segments(
     }
 }
 
+// Return the number of segments we expect to create based on the
+// SECTIONS clause.  This is used to implement SIZEOF_HEADERS.
+
+size_t
+Script_sections::expected_segment_count(const Layout* layout) const
+{
+  Layout::Section_list sections;
+  layout->get_allocated_sections(&sections);
+
+  // We assume that we will need two PT_LOAD segments.
+  size_t ret = 2;
+
+  bool saw_note = false;
+  bool saw_tls = false;
+  for (Layout::Section_list::const_iterator p = sections.begin();
+       p != sections.end();
+       ++p)
+    {
+      if ((*p)->type() == elfcpp::SHT_NOTE)
+       {
+         // Assume that all note sections will fit into a single
+         // PT_NOTE segment.
+         if (!saw_note)
+           {
+             ++ret;
+             saw_note = true;
+           }
+       }
+      else if (((*p)->flags() & elfcpp::SHF_TLS) != 0)
+       {
+         // There can only be one PT_TLS segment.
+         if (!saw_tls)
+           {
+             ++ret;
+             saw_tls = true;
+           }
+       }
+    }
+
+  return ret;
+}
+
 // Print the SECTIONS clause to F for debugging.
 
 void
index 6ac4303a490d7f933db30771d05ee67d5aabae7d..ec708bd50d1792879d5a8e636413ab48f953d679 100644 (file)
@@ -134,6 +134,11 @@ class Script_sections
   Output_segment*
   set_section_addresses(Symbol_table*, Layout*);
 
+  // Return the number of segments we expect to create based on the
+  // SECTIONS clause.
+  size_t
+  expected_segment_count(const Layout*) const;
+
   // Print the contents to the FILE.  This is for debugging.
   void
   print(FILE*) const;
index 734349b891d7ed0bb6d89cfd2106032b9f93b40b..973c05ce6df9d5c7c351e5da4a24622802689b80 100644 (file)
@@ -393,7 +393,9 @@ Lex::can_start_name(char c, char c2)
       return this->mode_ == LINKER_SCRIPT && can_continue_name(&c2);
 
     case '*': case '[': 
-      return this->mode_ == VERSION_SCRIPT;
+      return (this->mode_ == VERSION_SCRIPT
+             || (this->mode_ == LINKER_SCRIPT
+                 && can_continue_name(&c2)));
 
     default:
       return false;
@@ -1607,6 +1609,7 @@ script_keyword_parsecodes[] =
   { "SHORT", SHORT },
   { "SIZEOF", SIZEOF },
   { "SIZEOF_HEADERS", SIZEOF_HEADERS },
+  { "SORT", SORT_BY_NAME },
   { "SORT_BY_ALIGNMENT", SORT_BY_ALIGNMENT },
   { "SORT_BY_NAME", SORT_BY_NAME },
   { "SPECIAL", SPECIAL },
@@ -2145,6 +2148,24 @@ script_parse_option(void* closurev, const char* option, size_t length)
     }
 }
 
+// Called by the bison parser to handle SEARCH_DIR.  This is handled
+// exactly like a -L option.
+
+extern "C" void
+script_add_search_dir(void* closurev, const char* option, size_t length)
+{
+  Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+  if (closure->command_line() == NULL)
+    gold_warning(_("%s:%d:%d: ignoring SEARCH_DIR; SEARCH_DIR is only valid"
+                  " for scripts specified via -T/--script"),
+                closure->filename(), closure->lineno(), closure->charpos());
+  else
+    {
+      std::string s = "-L" + std::string(option, length);
+      script_parse_option(closurev, s.c_str(), s.size());
+    }
+}
+
 /* Called by the bison parser to push the lexer into expression
    mode.  */
 
index a0379063b55eb6cdadad2efed294875c1a6627d9..ad7670904f4fdcd4cd77ec96b790024a804c7e76 100644 (file)
@@ -60,6 +60,8 @@
   struct Parser_output_section_header output_section_header;
   /* An output section trailer.  */
   struct Parser_output_section_trailer output_section_trailer;
+  /* A section constraint.  */
+  enum Section_constraint constraint;
   /* A complete input section specification.  */
   struct Input_section_spec input_section_spec;
   /* A list of wildcard specifications, with exclusions.  */
 %type <expr> opt_at opt_align opt_subalign opt_fill
 %type <output_section_header> section_header
 %type <output_section_trailer> section_trailer
+%type <constraint> opt_constraint
 %type <integer> data_length
 %type <input_section_spec> input_section_no_keep
 %type <wildcard_sections> wildcard_sections
@@ -229,6 +232,8 @@ file_cmd:
            { script_end_group(closure); }
         | OPTION '(' string ')'
            { script_parse_option(closure, $3.value, $3.length); }
+       | SEARCH_DIR '(' string ')'
+           { script_add_search_dir(closure, $3.value, $3.length); }
        | SECTIONS '{'
            { script_start_sections(closure); }
          sections_block '}'
@@ -239,6 +244,7 @@ file_cmd:
             { script_pop_lex_mode(closure); }
        | file_or_sections_cmd
        | ignore_cmd
+       | ';'
        ;
 
 /* Top level commands which we ignore.  The GNU linker uses these to
@@ -287,12 +293,14 @@ section_block_cmd:
 section_header:
            { script_push_lex_into_expression_mode(closure); }
          opt_address_and_section_type opt_at opt_align opt_subalign
+           { script_pop_lex_mode(closure); }
+         opt_constraint
            {
              $$.address = $2;
              $$.load_address = $3;
              $$.align = $4;
              $$.subalign = $5;
-             script_pop_lex_mode(closure);
+             $$.constraint = $7;
            }
        ;
 
@@ -340,13 +348,23 @@ opt_subalign:
            { $$ = $3; }
        ;
 
+/* A section constraint.  */
+opt_constraint:
+         /* empty */
+           { $$ = CONSTRAINT_NONE; }
+       | ONLY_IF_RO
+           { $$ = CONSTRAINT_ONLY_IF_RO; }
+       | ONLY_IF_RW
+           { $$ = CONSTRAINT_ONLY_IF_RW; }
+       | SPECIAL
+           { $$ = CONSTRAINT_SPECIAL; }
+       ;
+
 /* The trailer of an output section in a SECTIONS block.  */
 section_trailer:
-           { script_push_lex_into_expression_mode(closure); }
          opt_memspec opt_at_memspec opt_phdr opt_fill opt_comma
            {
-             $$.fill = $5;
-             script_pop_lex_mode(closure);
+             $$.fill = $4;
            }
        ;
 
@@ -374,7 +392,7 @@ opt_phdr:
 /* The value to use to fill an output section.  FIXME: This does not
    handle a string of arbitrary length.  */
 opt_fill:
-         '=' exp
+         '=' parse_exp
            { $$ = $2; }
        | /* empty */
            { $$ = NULL; }
@@ -405,6 +423,7 @@ section_cmd:
                 some ELF linker scripts use it although it does
                 nothing, we accept it and ignore it.  */
            }
+       | SORT_BY_NAME '(' CONSTRUCTORS ')'
        | ';'
        ;