Change default to discard temporary local symbols in merge sections.

Add --discard-none to keep all local symbols.

2015-06-04  Cary Coutant  <ccoutant@gmail.com>

gold/
	PR gold/17498
	* object.cc (Sized_relobj_file::do_count_local_symbols): Discard
	temporary locals in merge sections.
	* options.cc (General_options::parse_discard_all): New method.
	(General_options::parse_discard_locals): New method.
	(General_options::parse_discard_none): New method.
	(General_options::General_options): Initialize discard_locals_.
	* options.h (--discard-all): Convert to special option.
	(--discard-locals): Likewise.
	(--discard-none): New option.
	(General_options::discard_all): New method.
	(General_options::discard_locals): New method.
	(General_options::discard_sec_merge): New method.
	(General_options::Discard_locals): New enum.
	(General_options::discard_locals_): New data member.


diff --git a/gold/object.cc b/gold/object.cc
index 18c6670..4e94f7e 100644
--- a/gold/object.cc
+++ b/gold/object.cc
@@ -2174,6 +2174,7 @@ Sized_relobj_file<size, big_endian>::do_count_local_symbols(Stringpool* pool,
   // Loop over the local symbols.
 
   const Output_sections& out_sections(this->output_sections());
+  std::vector<Address>& out_section_offsets(this->section_offsets());
   unsigned int shnum = this->shnum();
   unsigned int count = 0;
   unsigned int dyncount = 0;
@@ -2182,6 +2183,7 @@ Sized_relobj_file<size, big_endian>::do_count_local_symbols(Stringpool* pool,
   bool strip_all = parameters->options().strip_all();
   bool discard_all = parameters->options().discard_all();
   bool discard_locals = parameters->options().discard_locals();
+  bool discard_sec_merge = parameters->options().discard_sec_merge();
   for (unsigned int i = 1; i < loccount; ++i, psyms += sym_size)
     {
       elfcpp::Sym<size, big_endian> sym(psyms);
@@ -2246,6 +2248,7 @@ Sized_relobj_file<size, big_endian>::do_count_local_symbols(Stringpool* pool,
 	  continue;
 	}
 
+      // By default, discard temporary local symbols in merge sections.
       // If --discard-locals option is used, discard all temporary local
       // symbols.  These symbols start with system-specific local label
       // prefixes, typically .L for ELF system.  We want to be compatible
@@ -2258,7 +2261,10 @@ Sized_relobj_file<size, big_endian>::do_count_local_symbols(Stringpool* pool,
       //   - the symbol has a name.
       //
       // We do not discard a symbol if it needs a dynamic symbol entry.
-      if (discard_locals
+      if ((discard_locals
+	   || (discard_sec_merge
+	       && is_ordinary
+	       && out_section_offsets[shndx] == invalid_address))
 	  && sym.get_st_type() != elfcpp::STT_FILE
 	  && !lv.needs_output_dynsym_entry()
 	  && lv.may_be_discarded_from_output_symtab()
diff --git a/gold/options.cc b/gold/options.cc
index 39dc311..c42623f 100644
--- a/gold/options.cc
+++ b/gold/options.cc
@@ -346,6 +346,27 @@ General_options::parse_defsym(const char*, const char* arg,
 }
 
 void
+General_options::parse_discard_all(const char*, const char*,
+				   Command_line*)
+{
+  this->discard_locals_ = DISCARD_ALL;
+}
+
+void
+General_options::parse_discard_locals(const char*, const char*,
+				      Command_line*)
+{
+  this->discard_locals_ = DISCARD_LOCALS;
+}
+
+void
+General_options::parse_discard_none(const char*, const char*,
+				    Command_line*)
+{
+  this->discard_locals_ = DISCARD_NONE;
+}
+
+void
 General_options::parse_incremental(const char*, const char*,
 				   Command_line*)
 {
@@ -927,7 +948,8 @@ General_options::General_options()
     symbols_to_retain_(),
     section_starts_(),
     fix_v4bx_(FIX_V4BX_NONE),
-    endianness_(ENDIANNESS_NOT_SET)
+    endianness_(ENDIANNESS_NOT_SET),
+    discard_locals_(DISCARD_SEC_MERGE)
 {
   // Turn off option registration once construction is complete.
   gold::options::ready_to_register = false;
diff --git a/gold/options.h b/gold/options.h
index 67eb1b2..658ad42 100644
--- a/gold/options.h
+++ b/gold/options.h
@@ -739,10 +739,12 @@ class General_options
 	      N_("Look for violations of the C++ One Definition Rule"),
 	      N_("Do not look for violations of the C++ One Definition Rule"));
 
-  DEFINE_bool(discard_all, options::TWO_DASHES, 'x', false,
-	      N_("Delete all local symbols"), NULL);
-  DEFINE_bool(discard_locals, options::TWO_DASHES, 'X', false,
-	      N_("Delete all temporary local symbols"), NULL);
+  DEFINE_special(discard_all, options::TWO_DASHES, 'x',
+		 N_("Delete all local symbols"), NULL);
+  DEFINE_special(discard_locals, options::TWO_DASHES, 'X',
+		 N_("Delete all temporary local symbols"), NULL);
+  DEFINE_special(discard_none, options::TWO_DASHES, '\0',
+		 N_("Keep all local symbols"), NULL);
 
   DEFINE_bool(dynamic_list_data, options::TWO_DASHES, '\0', false,
 	      N_("Add data symbols to dynamic symbols"), NULL);
@@ -1526,11 +1528,36 @@ class General_options
   endianness() const
   { return this->endianness_; }
 
+  bool
+  discard_all() const
+  { return this->discard_locals_ == DISCARD_ALL; }
+
+  bool
+  discard_locals() const
+  { return this->discard_locals_ == DISCARD_LOCALS; }
+
+  bool
+  discard_sec_merge() const
+  { return this->discard_locals_ == DISCARD_SEC_MERGE; }
+
  private:
   // Don't copy this structure.
   General_options(const General_options&);
   General_options& operator=(const General_options&);
 
+  // What local symbols to discard.
+  enum Discard_locals
+  {
+    // Locals in merge sections (default).
+    DISCARD_SEC_MERGE,
+    // None (--discard-none).
+    DISCARD_NONE,
+    // Temporary locals (--discard-locals/-X).
+    DISCARD_LOCALS,
+    // All locals (--discard-all/-x).
+    DISCARD_ALL
+  };
+
   // Whether to mark the stack as executable.
   enum Execstack
   {
@@ -1626,6 +1653,8 @@ class General_options
   Fix_v4bx fix_v4bx_;
   // Endianness.
   Endianness endianness_;
+  // What local symbols to discard.
+  Discard_locals discard_locals_;
 };
 
 // The position-dependent options.  We use this to store the state of
