OSDN Git Service

Add support for PT_GNU_STACK.
authoriant <iant>
Tue, 23 Oct 2007 05:05:48 +0000 (05:05 +0000)
committeriant <iant>
Tue, 23 Oct 2007 05:05:48 +0000 (05:05 +0000)
13 files changed:
gold/dynobj.cc
gold/dynobj.h
gold/i386.cc
gold/layout.cc
gold/layout.h
gold/object.cc
gold/options.cc
gold/options.h
gold/symtab.cc
gold/symtab.h
gold/target.h
gold/testsuite/testfile.cc
gold/x86_64.cc

index 499eda7..119f0c7 100644 (file)
@@ -1210,8 +1210,7 @@ Versions::get_dynobj_for_sym(const Symbol_table* symtab,
 // symbol table.
 
 void
-Versions::record_version(const General_options* options,
-                        const Symbol_table* symtab,
+Versions::record_version(const Symbol_table* symtab,
                         Stringpool* dynpool, const Symbol* sym)
 {
   gold_assert(!this->is_finalized_);
@@ -1223,7 +1222,7 @@ Versions::record_version(const General_options* options,
   if (!sym->is_from_dynobj() && !sym->is_copied_from_dynobj())
     {
       if (parameters->output_is_shared())
-        this->add_def(options, sym, version, version_key);
+        this->add_def(sym, version, version_key);
     }
   else
     {
@@ -1236,8 +1235,8 @@ Versions::record_version(const General_options* options,
 // We've found a symbol SYM defined in version VERSION.
 
 void
-Versions::add_def(const General_options* options, const Symbol* sym,
-                 const char* version, Stringpool::Key version_key)
+Versions::add_def(const Symbol* sym, const char* version,
+                 Stringpool::Key version_key)
 {
   Key k(version_key, 0);
   Version_base* const vbnull = NULL;
@@ -1271,7 +1270,7 @@ Versions::add_def(const General_options* options, const Symbol* sym,
       // If this is the first version we are defining, first define
       // the base version.  FIXME: Should use soname here when
       // creating a shared object.
-      Verdef* vdbase = new Verdef(options->output_file_name(), true, false,
+      Verdef* vdbase = new Verdef(parameters->output_file_name(), true, false,
                                  true);
       this->defs_.push_back(vdbase);
 
index 78caaf9..a3d733d 100644 (file)
@@ -411,8 +411,7 @@ class Versions
   // SYM is going into the dynamic symbol table and has a version.
   // Record the appropriate version information.
   void
-  record_version(const General_options*, const Symbol_table* symtab,
-                Stringpool*, const Symbol* sym);
+  record_version(const Symbol_table* symtab, Stringpool*, const Symbol* sym);
 
   // Set the version indexes.  DYNSYM_INDEX is the index we should use
   // for the next dynamic symbol.  We add new dynamic symbols to SYMS
@@ -466,8 +465,7 @@ class Versions
 
   // Handle a symbol SYM defined with version VERSION.
   void
-  add_def(const General_options*, const Symbol* sym, const char* version,
-         Stringpool::Key);
+  add_def(const Symbol* sym, const char* version, Stringpool::Key);
 
   // Add a reference to version NAME in file FILENAME.
   void
index 26888bf..e36b22c 100644 (file)
@@ -263,6 +263,7 @@ const Target::Target_info Target_i386::i386_info =
   false,               // has_make_symbol
   false,               // has_resolve
   true,                        // has_code_fill
+  true,                        // is_default_stack_executable
   "/usr/lib/libc.so.1",        // dynamic_linker
   0x08048000,          // default_text_segment_address
   0x1000,              // abi_pagesize
index ae2b23f..22d3b59 100644 (file)
@@ -67,7 +67,10 @@ Layout::Layout(const General_options& options)
     unattached_section_list_(), special_output_list_(),
     tls_segment_(NULL), symtab_section_(NULL),
     dynsym_section_(NULL), dynamic_section_(NULL), dynamic_data_(NULL),
-    eh_frame_section_(NULL), output_file_size_(-1)
+    eh_frame_section_(NULL), output_file_size_(-1),
+    input_requires_executable_stack_(false),
+    input_with_gnu_stack_note_(false),
+    input_without_gnu_stack_note_(false)
 {
   // Make space for more than enough segments for a typical file.
   // This is just for efficiency--it's OK if we wind up needing more.
@@ -404,6 +407,27 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type,
   return os;
 }
 
+// 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
+// protection required for stack memory.  We record this in an
+// executable as a PT_GNU_STACK segment.  If an object file does not
+// have a .note.GNU-stack segment, we must assume that it is an old
+// object.  On some targets that will force an executable stack.
+
+void
+Layout::layout_gnu_stack(bool seen_gnu_stack, uint64_t gnu_stack_flags)
+{
+  if (!seen_gnu_stack)
+    this->input_without_gnu_stack_note_ = true;
+  else
+    {
+      this->input_with_gnu_stack_note_ = true;
+      if ((gnu_stack_flags & elfcpp::SHF_EXECINSTR) != 0)
+       this->input_requires_executable_stack_ = true;
+    }
+}
+
 // Create the dynamic sections which are needed before we read the
 // relocs.
 
@@ -542,7 +566,8 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
 
   target->finalize_sections(this);
 
-  this->create_note_section();
+  this->create_gold_note();
+  this->create_executable_stack_info(target);
 
   Output_segment* phdr_seg = NULL;
   if (!parameters->doing_static_link())
@@ -635,7 +660,7 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
 // records the version of gold used to create the binary.
 
 void
-Layout::create_note_section()
+Layout::create_gold_note()
 {
   if (parameters->output_is_object())
     return;
@@ -651,7 +676,7 @@ Layout::create_note_section()
   // version 2.16.91), and glibc always generates the latter for
   // .note.ABI-tag (as of version 1.6), so that's the one we go with
   // here.
-#ifdef GABI_FORMAT_FOR_DOTNOTE_SECTION   // this is not defined by default
+#ifdef GABI_FORMAT_FOR_DOTNOTE_SECTION   // This is not defined by default.
   const int size = parameters->get_size();
 #else
   const int size = 32;
@@ -719,6 +744,54 @@ Layout::create_note_section()
   os->add_output_section_data(posd);
 }
 
+// Record whether the stack should be executable.  This can be set
+// from the command line using the -z execstack or -z noexecstack
+// options.  Otherwise, if any input file has a .note.GNU-stack
+// section with the SHF_EXECINSTR flag set, the stack should be
+// executable.  Otherwise, if at least one input file a
+// .note.GNU-stack section, and some input file has no .note.GNU-stack
+// section, we use the target default for whether the stack should be
+// executable.  Otherwise, we don't generate a stack note.  When
+// generating a object file, we create a .note.GNU-stack section with
+// the appropriate marking.  When generating an executable or shared
+// library, we create a PT_GNU_STACK segment.
+
+void
+Layout::create_executable_stack_info(const Target* target)
+{
+  bool is_stack_executable;
+  if (this->options_.is_execstack_set())
+    is_stack_executable = this->options_.is_stack_executable();
+  else if (!this->input_with_gnu_stack_note_)
+    return;
+  else
+    {
+      if (this->input_requires_executable_stack_)
+       is_stack_executable = true;
+      else if (this->input_without_gnu_stack_note_)
+       is_stack_executable = target->is_default_stack_executable();
+      else
+       is_stack_executable = false;
+    }
+
+  if (parameters->output_is_object())
+    {
+      const char* name = this->namepool_.add(".note.GNU-stack", false, NULL);
+      elfcpp::Elf_Xword flags = 0;
+      if (is_stack_executable)
+       flags |= elfcpp::SHF_EXECINSTR;
+      this->make_output_section(name, elfcpp::SHT_PROGBITS, flags);
+    }
+  else
+    {
+      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);
+    }
+}
+
 // 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.
@@ -1126,9 +1199,8 @@ Layout::create_dynamic_symtab(const Target* target, Symbol_table* symtab,
 
   // FIXME: We have to tell set_dynsym_indexes whether the
   // -E/--export-dynamic option was used.
-  index = symtab->set_dynsym_indexes(&this->options_, target, index,
-                                    pdynamic_symbols, &this->dynpool_,
-                                    pversions);
+  index = symtab->set_dynsym_indexes(target, index, pdynamic_symbols,
+                                    &this->dynpool_, pversions);
 
   int symsize;
   unsigned int align;
index 409290a..19c8e09 100644 (file)
@@ -94,6 +94,13 @@ class Layout
   layout(Relobj *object, unsigned int shndx, const char* name,
         const elfcpp::Shdr<size, big_endian>& shdr, off_t* offset);
 
+  // Handle a GNU stack note.  This is called once per input object
+  // file.  SEEN_GNU_STACK is true if the object file has a
+  // .note.GNU-stack section.  GNU_STACK_FLAGS is the section flags
+  // from that section if there was one.
+  void
+  layout_gnu_stack(bool seen_gnu_stack, uint64_t gnu_stack_flags);
+
   // Add an Output_section_data to the layout.  This is used for
   // special sections like the GOT section.
   void
@@ -220,7 +227,11 @@ class Layout
 
   // Create a .note section for gold.
   void
-  create_note_section();
+  create_gold_note();
+
+  // Record whether the stack must be executable.
+  void
+  create_executable_stack_info(const Target*);
 
   // Find the first read-only PT_LOAD segment, creating one if
   // necessary.
@@ -377,6 +388,15 @@ class Layout
   Output_section* eh_frame_section_;
   // The size of the output file.
   off_t output_file_size_;
+  // Whether we have seen an object file marked to require an
+  // executable stack.
+  bool input_requires_executable_stack_;
+  // Whether we have seen at least one object file with an executable
+  // stack marker.
+  bool input_with_gnu_stack_note_;
+  // Whether we have seen at least one object file without an
+  // executable stack marker.
+  bool input_without_gnu_stack_note_;
 };
 
 // This task handles writing out data which is not part of a section
index 64cecc8..9e4b58d 100644 (file)
@@ -427,6 +427,11 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
   std::vector<Map_to_output>& map_sections(this->map_to_output());
   map_sections.resize(shnum);
 
+  // Whether we've seen a .note.GNU-stack section.
+  bool seen_gnu_stack = false;
+  // The flags of a .note.GNU-stack section.
+  uint64_t gnu_stack_flags = 0;
+
   // Keep track of which sections to omit.
   std::vector<bool> omit(shnum, false);
 
@@ -451,6 +456,16 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
            omit[i] = true;
        }
 
+      // The .note.GNU-stack section is special.  It gives the
+      // protection flags that this object file requires for the stack
+      // in memory.
+      if (strcmp(name, ".note.GNU-stack") == 0)
+       {
+         seen_gnu_stack = true;
+         gnu_stack_flags |= shdr.get_sh_flags();
+         omit[i] = true;
+       }
+
       bool discard = omit[i];
       if (!discard)
        {
@@ -481,6 +496,8 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
       map_sections[i].offset = offset;
     }
 
+  layout->layout_gnu_stack(seen_gnu_stack, gnu_stack_flags);
+
   delete sd->section_headers;
   sd->section_headers = NULL;
   delete sd->section_names;
index 4e74dce..1e4b90e 100644 (file)
@@ -93,11 +93,24 @@ struct options::One_option
   { return this->general_arg != NULL || this->dependent_arg != NULL; }
 };
 
+// We have a separate table for -z options.
+
+struct options::One_z_option
+{
+  // The name of the option.
+  const char* name;
+
+  // The member function in General_options called to record it.
+  void (General_options::*set)();
+};
+
 class options::Command_line_options
 {
  public:
   static const One_option options[];
   static const int options_size;
+  static const One_z_option z_options[];
+  static const int z_options_size;
 };
 
 } // End namespace gold.
@@ -394,6 +407,14 @@ options::Command_line_options::options[] =
                N_("Include only needed archive contents"),
                NULL, TWO_DASHES,
                &Position_dependent_options::clear_whole_archive),
+
+  GENERAL_ARG('z', NULL,
+             N_("Subcommands as follows:\n\
+    -z execstack              Mark output as requiring executable stack\n\
+    -z noexecstack            Mark output as not requiring executable stack"),
+             N_("-z SUBCOMMAND"), ONE_DASH,
+             &General_options::handle_z_option),
+
   SPECIAL('(', "start-group", N_("Start a library search group"), NULL,
          TWO_DASHES, &start_group),
   SPECIAL(')', "end-group", N_("End a library search group"), NULL,
@@ -407,6 +428,18 @@ options::Command_line_options::options[] =
 const int options::Command_line_options::options_size =
   sizeof (options) / sizeof (options[0]);
 
+// The -z options.
+
+const options::One_z_option
+options::Command_line_options::z_options[] =
+{
+  { "execstack", &General_options::set_execstack },
+  { "noexecstack", &General_options::set_noexecstack },
+};
+
+const int options::Command_line_options::z_options_size =
+  sizeof(z_options) / sizeof(z_options[0]);
+
 // The default values for the general options.
 
 General_options::General_options()
@@ -429,7 +462,8 @@ General_options::General_options()
     threads_(false),
     thread_count_initial_(0),
     thread_count_middle_(0),
-    thread_count_final_(0)
+    thread_count_final_(0),
+    execstack_(EXECSTACK_FROM_INPUT)
 {
 }
 
@@ -442,6 +476,28 @@ Position_dependent_options::Position_dependent_options()
 {
 }
 
+// Handle the -z option.
+
+void
+General_options::handle_z_option(const char* arg)
+{
+  const int z_options_size = options::Command_line_options::z_options_size;
+  const gold::options::One_z_option* z_options =
+    gold::options::Command_line_options::z_options;
+  for (int i = 0; i < z_options_size; ++i)
+    {
+      if (strcmp(arg, z_options[i].name) == 0)
+       {
+         (this->*(z_options[i].set))();
+         return;
+       }
+    }
+
+  fprintf(stderr, _("%s: unrecognized -z subcommand: %s\n"),
+         program_name, arg);
+  ::exit(1);
+}
+
 // Add the sysroot, if any, to the search paths.
 
 void
@@ -686,7 +742,7 @@ Command_line::process(int argc, char** argv)
 
   if (this->inputs_.in_group())
     {
-      fprintf(stderr, _("%s: missing group end"), program_name);
+      fprintf(stderr, _("%s: missing group end\n"), program_name);
       this->usage();
     }
 
index f9782cc..dad1c90 100644 (file)
@@ -47,6 +47,7 @@ namespace options {
 
 class Command_line_options;
 struct One_option;
+struct One_z_option;
 
 } // End namespace gold::options.
 
@@ -214,6 +215,15 @@ class General_options
   thread_count_final() const
   { return this->thread_count_final_; }
 
+  // -z execstack, -z noexecstack
+  bool
+  is_execstack_set() const
+  { return this->execstack_ != EXECSTACK_FROM_INPUT; }
+
+  bool
+  is_stack_executable() const
+  { return this->execstack_ == EXECSTACK_YES; }
+
  private:
   // Don't copy this structure.
   General_options(const General_options&);
@@ -233,6 +243,17 @@ class General_options
     STRIP_DEBUG
   };
 
+  // Whether to mark the stack as executable.
+  enum Execstack
+  {
+    // Not set on command line.
+    EXECSTACK_FROM_INPUT,
+    // Mark the stack as executable.
+    EXECSTACK_YES,
+    // Mark the stack as not executable.
+    EXECSTACK_NO
+  };
+
   void
   set_export_dynamic()
   { this->export_dynamic_ = true; }
@@ -364,6 +385,18 @@ class General_options
   ignore(const char*)
   { }
 
+  void
+  set_execstack()
+  { this->execstack_ = EXECSTACK_YES; }
+
+  void
+  set_noexecstack()
+  { this->execstack_ = EXECSTACK_NO; }
+
+  // Handle the -z option.
+  void
+  handle_z_option(const char*);
+
   // Apply any sysroot to the directory lists.
   void
   add_sysroot();
@@ -388,6 +421,7 @@ class General_options
   int thread_count_initial_;
   int thread_count_middle_;
   int thread_count_final_;
+  Execstack execstack_;
 };
 
 // The current state of the position dependent options.
index 1f120dd..3108433 100644 (file)
@@ -1294,8 +1294,7 @@ Symbol_table::get_copy_source(const Symbol* sym) const
 // updated dynamic symbol index.
 
 unsigned int
-Symbol_table::set_dynsym_indexes(const General_options* options,
-                                const Target* target,
+Symbol_table::set_dynsym_indexes(const Target* target,
                                 unsigned int index,
                                 std::vector<Symbol*>* syms,
                                 Stringpool* dynpool,
@@ -1322,7 +1321,7 @@ Symbol_table::set_dynsym_indexes(const General_options* options,
 
          // Record any version information.
          if (sym->version() != NULL)
-           versions->record_version(options, this, dynpool, sym);
+           versions->record_version(this, dynpool, sym);
        }
     }
 
index 49ceb7a..05c8d7a 100644 (file)
@@ -947,7 +947,7 @@ class Symbol_table
   // the vector.  The names are stored into the Stringpool.  This
   // returns an updated dynamic symbol index.
   unsigned int
-  set_dynsym_indexes(const General_options*, const Target*, unsigned int index,
+  set_dynsym_indexes(const Target*, unsigned int index,
                     std::vector<Symbol*>*, Stringpool*, Versions*);
 
   // Finalize the symbol table after we have set the final addresses
index 3908174..32166d1 100644 (file)
@@ -108,6 +108,14 @@ class Target
   common_pagesize() const
   { return this->pti_->common_pagesize; }
 
+  // If we see some object files with .note.GNU-stack sections, and
+  // some objects files without them, this returns whether we should
+  // consider the object files without them to imply that the stack
+  // should be executable.
+  bool
+  is_default_stack_executable() const
+  { return this->pti_->is_default_stack_executable; }
+
   // This is called to tell the target to complete any sections it is
   // handling.  After this all sections must have their final size.
   void
@@ -146,6 +154,9 @@ class Target
     bool has_resolve;
     // Whether this target has a specific code fill function.
     bool has_code_fill;
+    // Whether an object file with no .note.GNU-stack sections implies
+    // that the stack should be executable.
+    bool is_default_stack_executable;
     // The default dynamic linker name.
     const char* dynamic_linker;
     // The default text segment address.
index 116c6b6..8e6a48d 100644 (file)
@@ -68,6 +68,7 @@ const Target::Target_info Target_test<size, big_endian>::test_target_info =
   false,                               // has_make_symbol
   false,                               // has_resolve
   false,                               // has_code_fill
+  false,                               // is_default_stack_executable
   "/dummy",                            // dynamic_linker
   0x08000000,                          // default_text_segment_address
   0x1000,                              // abi_pagesize
index 0af7a16..c520375 100644 (file)
@@ -263,6 +263,7 @@ const Target::Target_info Target_x86_64::x86_64_info =
   false,               // has_make_symbol
   false,               // has_resolve
   true,                        // has_code_fill
+  true,                        // is_default_stack_executable
   "/lib/ld64.so.1",     // program interpreter
   0x400000,            // default_text_segment_address
   0x1000,              // abi_pagesize