[GOLD] PR24853, OSABI not set when STT_GNU_IFUNC or STB_GNU_UNIQUE symbols output

Message ID 20191002132938.GB7064@bubble.grove.modra.org
State New
Headers show
Series
  • [GOLD] PR24853, OSABI not set when STT_GNU_IFUNC or STB_GNU_UNIQUE symbols output
Related show

Commit Message

Alan Modra Oct. 2, 2019, 1:29 p.m.
This patch arranges to have OSABI set to ELFOSABI_GNU (if not set to
some other non-zero value) when gold outputs an ifunc local or global
symbol, or a unique global symbol to either .dynsym or .symtab.
STT_GNU_IFUNC and STB_GNU_UNIQUE have values in the LOOS to HIOS range
and therefore require interpretation according to OSABI.  (There are a
number of other values that really ought to require ELFOSABI_GNU too,
eg. SHT_GNU_HASH or PT_GNU_EH_FRAME but the symbol values are from a
very small range, and we know of clashes.)

I'm not sure why parameters->target() is const Target& while
parameters->sized_target() is Sized_target*, but it's inconvenient to
use the latter in Symbol_table::finalize.  So this patch adds another
const_cast complained about in layout.cc and gold.cc.  I'll happily
change parameters->target() to return a Target* and adjust all uses if
you'd like.

OK to apply?

	PR 24853
	* symtab.h (set_has_gnu_output, has_gnu_output_): New.
	* symtab.cc (Symbol_table::Symbol_table): Init has_gnu_output_.
	(Symbol_table::finalize): Set ELFOSABI_GNU when has_gnu_output_.
	(Symbol_table::set_dynsym_indexes, add_to_final_symtab): Call
	set_has_gnu_output for STT_GNU_IFUNC and STB_GNU_UNIQUE globals.
	* object.cc (Sized_relobj_file::do_finalize_local_symbols): Call
	set_has_gnu_output when STT_GNU_IFUNC locals will be output.


-- 
Alan Modra
Australia Development Lab, IBM

Comments

Alan Modra Oct. 2, 2019, 11:15 p.m. | #1
On Wed, Oct 02, 2019 at 10:59:38PM +0930, Alan Modra wrote:
> @@ -2711,6 +2730,10 @@ void

>  Symbol_table::add_to_final_symtab(Symbol* sym, Stringpool* pool,

>  				  unsigned int* pindex, off_t* poff)

>  {

> +  if (sym->type() == elfcpp::STT_GNU_IFUNC

> +      || (sym->binding() == elfcpp::STB_GNU_UNIQUE

> +	  && parameters->options().gnu_unique()))

> +    this->set_has_gnu_output();

>    sym->set_symtab_index(*pindex);

>    if (sym->version() == NULL || !parameters->options().relocatable())

>      pool->add(sym->name(), false, NULL);


This part wasn't correct, sorry.  Unique symbols that have been forced
local for some reason will still have STB_GNU_UNIQUE binding at this
stage.  The following revision moves the add_to_final_symtab changes
into that function's caller, where we just look for ifunc symbols on
the forced_locals_ list.

	PR 24853
	* symtab.h (set_has_gnu_output, has_gnu_output_): New.
	* symtab.cc (Symbol_table::Symbol_table): Init has_gnu_output_.
	(Symbol_table::finalize): Set ELFOSABI_GNU when has_gnu_output_.
	(Symbol_table::set_dynsym_indexes, Symbol_table::sized_finalize):
	Call set_has_gnu_output for STT_GNU_IFUNC and STB_GNU_UNIQUE globals.
	* object.cc (Sized_relobj_file::do_finalize_local_symbols): Call
	set_has_gnu_output when STT_GNU_IFUNC locals will be output.

diff --git a/gold/object.cc b/gold/object.cc
index 2fca7eb227..959cbc5f27 100644
--- a/gold/object.cc
+++ b/gold/object.cc
@@ -2646,6 +2646,10 @@ Sized_relobj_file<size, big_endian>::do_finalize_local_symbols(
 	      lv->set_output_symtab_index(index);
 	      ++index;
 	    }
+	  if (lv->is_ifunc_symbol()
+	      && (lv->has_output_symtab_entry()
+		  || lv->needs_output_dynsym_entry()))
+	    symtab->set_has_gnu_output();
 	  break;
 	case CFLV_DISCARDED:
 	case CFLV_ERROR:
diff --git a/gold/symtab.cc b/gold/symtab.cc
index 56d1e42b8b..99e97210bd 100644
--- a/gold/symtab.cc
+++ b/gold/symtab.cc
@@ -565,8 +565,8 @@ Symbol::set_undefined()
 
 Symbol_table::Symbol_table(unsigned int count,
                            const Version_script_info& version_script)
-  : saw_undefined_(0), offset_(0), table_(count), namepool_(),
-    forwarders_(), commons_(), tls_commons_(), small_commons_(),
+  : saw_undefined_(0), offset_(0), has_gnu_output_(false), table_(count),
+    namepool_(), forwarders_(), commons_(), tls_commons_(), small_commons_(),
     large_commons_(), forced_locals_(), warnings_(),
     version_script_(version_script), gc_(NULL), icf_(NULL),
     target_symbols_()
@@ -2565,6 +2565,8 @@ Symbol_table::set_dynsym_indexes(unsigned int index,
           ++index;
           ++forced_local_count;
 	  dynpool->add(sym->name(), false, NULL);
+	  if (sym->type() == elfcpp::STT_GNU_IFUNC)
+	    this->set_has_gnu_output();
         }
     }
   *pforced_local_count = forced_local_count;
@@ -2583,7 +2585,13 @@ Symbol_table::set_dynsym_indexes(unsigned int index,
           if (!sym->should_add_dynsym_entry(this))
             sym->set_dynsym_index(-1U);
           else
-            dyn_symbols.push_back(sym);
+	    {
+	      dyn_symbols.push_back(sym);
+	      if (sym->type() == elfcpp::STT_GNU_IFUNC
+		  || (sym->binding() == elfcpp::STB_GNU_UNIQUE
+		      && parameters->options().gnu_unique()))
+		this->set_has_gnu_output();
+	    }
         }
 
       return parameters->target().set_dynsym_indexes(&dyn_symbols, index, syms,
@@ -2611,6 +2619,10 @@ Symbol_table::set_dynsym_indexes(unsigned int index,
 	  ++index;
 	  syms->push_back(sym);
 	  dynpool->add(sym->name(), false, NULL);
+	  if (sym->type() == elfcpp::STT_GNU_IFUNC
+	      || (sym->binding() == elfcpp::STB_GNU_UNIQUE
+		  && parameters->options().gnu_unique()))
+	    this->set_has_gnu_output();
 
 	  // Record any version information, except those from
 	  // as-needed libraries not seen to be needed.  Note that the
@@ -2696,6 +2708,13 @@ Symbol_table::finalize(off_t off, off_t dynoff, size_t dyn_global_index,
   else
     gold_unreachable();
 
+  if (this->has_gnu_output_)
+    {
+      Target* target = const_cast<Target*>(&parameters->target());
+      if (target->osabi() == elfcpp::ELFOSABI_NONE)
+	target->set_osabi(elfcpp::ELFOSABI_GNU);
+    }
+
   // Now that we have the final symbol table, we can reliably note
   // which symbols should get warnings.
   this->warnings_.note_warnings(this);
@@ -2747,6 +2766,8 @@ Symbol_table::sized_finalize(off_t off, Stringpool* pool,
 	{
 	  this->add_to_final_symtab<size>(sym, pool, &index, &off);
 	  ++*plocal_symcount;
+	  if (sym->type() == elfcpp::STT_GNU_IFUNC)
+	    this->set_has_gnu_output();
 	}
     }
 
@@ -2757,7 +2778,13 @@ Symbol_table::sized_finalize(off_t off, Stringpool* pool,
     {
       Symbol* sym = p->second;
       if (this->sized_finalize_symbol<size>(sym))
-	this->add_to_final_symtab<size>(sym, pool, &index, &off);
+	{
+	  this->add_to_final_symtab<size>(sym, pool, &index, &off);
+	  if (sym->type() == elfcpp::STT_GNU_IFUNC
+	      || (sym->binding() == elfcpp::STB_GNU_UNIQUE
+		  && parameters->options().gnu_unique()))
+	    this->set_has_gnu_output();
+	}
     }
 
   // Now do target-specific symbols.
diff --git a/gold/symtab.h b/gold/symtab.h
index a9e8dd3278..dd931f5f04 100644
--- a/gold/symtab.h
+++ b/gold/symtab.h
@@ -1580,6 +1580,10 @@ class Symbol_table
   saw_undefined() const
   { return this->saw_undefined_; }
 
+  void
+  set_has_gnu_output()
+  { this->has_gnu_output_ = true; }
+
   // Allocate the common symbols
   void
   allocate_commons(Layout*, Mapfile*);
@@ -1981,6 +1985,8 @@ class Symbol_table
   // The number of global dynamic symbols (including forced-local symbols),
   // or 0 if none.
   unsigned int dynamic_count_;
+  // Set if a STT_GNU_IFUNC or STB_GNU_UNIQUE symbol will be output.
+  bool has_gnu_output_;
   // The symbol hash table.
   Symbol_table_type table_;
   // A pool of symbol names.  This is used for all global symbols.


-- 
Alan Modra
Australia Development Lab, IBM
Alan Modra Oct. 16, 2019, 3:07 a.m. | #2
On Thu, Oct 03, 2019 at 08:45:29AM +0930, Alan Modra wrote:
> 	PR 24853

> 	* symtab.h (set_has_gnu_output, has_gnu_output_): New.

> 	* symtab.cc (Symbol_table::Symbol_table): Init has_gnu_output_.

> 	(Symbol_table::finalize): Set ELFOSABI_GNU when has_gnu_output_.

> 	(Symbol_table::set_dynsym_indexes, Symbol_table::sized_finalize):

> 	Call set_has_gnu_output for STT_GNU_IFUNC and STB_GNU_UNIQUE globals.

> 	* object.cc (Sized_relobj_file::do_finalize_local_symbols): Call

> 	set_has_gnu_output when STT_GNU_IFUNC locals will be output.


Ping?

-- 
Alan Modra
Australia Development Lab, IBM
Alan Modra Nov. 18, 2019, 9:34 p.m. | #3
On Wed, Oct 16, 2019 at 01:37:22PM +1030, Alan Modra wrote:
> On Thu, Oct 03, 2019 at 08:45:29AM +0930, Alan Modra wrote:

> > 	PR 24853

> > 	* symtab.h (set_has_gnu_output, has_gnu_output_): New.

> > 	* symtab.cc (Symbol_table::Symbol_table): Init has_gnu_output_.

> > 	(Symbol_table::finalize): Set ELFOSABI_GNU when has_gnu_output_.

> > 	(Symbol_table::set_dynsym_indexes, Symbol_table::sized_finalize):

> > 	Call set_has_gnu_output for STT_GNU_IFUNC and STB_GNU_UNIQUE globals.

> > 	* object.cc (Sized_relobj_file::do_finalize_local_symbols): Call

> > 	set_has_gnu_output when STT_GNU_IFUNC locals will be output.

> 

> Ping?


I've committed this patch.  I figure the design at least is reasonably
obvious.

-- 
Alan Modra
Australia Development Lab, IBM

Patch

diff --git a/gold/object.cc b/gold/object.cc
index 2fca7eb227..959cbc5f27 100644
--- a/gold/object.cc
+++ b/gold/object.cc
@@ -2646,6 +2646,10 @@  Sized_relobj_file<size, big_endian>::do_finalize_local_symbols(
 	      lv->set_output_symtab_index(index);
 	      ++index;
 	    }
+	  if (lv->is_ifunc_symbol()
+	      && (lv->has_output_symtab_entry()
+		  || lv->needs_output_dynsym_entry()))
+	    symtab->set_has_gnu_output();
 	  break;
 	case CFLV_DISCARDED:
 	case CFLV_ERROR:
diff --git a/gold/symtab.cc b/gold/symtab.cc
index 56d1e42b8b..d46cbd2cbc 100644
--- a/gold/symtab.cc
+++ b/gold/symtab.cc
@@ -565,8 +565,8 @@  Symbol::set_undefined()
 
 Symbol_table::Symbol_table(unsigned int count,
                            const Version_script_info& version_script)
-  : saw_undefined_(0), offset_(0), table_(count), namepool_(),
-    forwarders_(), commons_(), tls_commons_(), small_commons_(),
+  : saw_undefined_(0), offset_(0), has_gnu_output_(false), table_(count),
+    namepool_(), forwarders_(), commons_(), tls_commons_(), small_commons_(),
     large_commons_(), forced_locals_(), warnings_(),
     version_script_(version_script), gc_(NULL), icf_(NULL),
     target_symbols_()
@@ -2565,6 +2565,8 @@  Symbol_table::set_dynsym_indexes(unsigned int index,
           ++index;
           ++forced_local_count;
 	  dynpool->add(sym->name(), false, NULL);
+	  if (sym->type() == elfcpp::STT_GNU_IFUNC)
+	    this->set_has_gnu_output();
         }
     }
   *pforced_local_count = forced_local_count;
@@ -2583,7 +2585,13 @@  Symbol_table::set_dynsym_indexes(unsigned int index,
           if (!sym->should_add_dynsym_entry(this))
             sym->set_dynsym_index(-1U);
           else
-            dyn_symbols.push_back(sym);
+	    {
+	      dyn_symbols.push_back(sym);
+	      if (sym->type() == elfcpp::STT_GNU_IFUNC
+		  || (sym->binding() == elfcpp::STB_GNU_UNIQUE
+		      && parameters->options().gnu_unique()))
+		this->set_has_gnu_output();
+	    }
         }
 
       return parameters->target().set_dynsym_indexes(&dyn_symbols, index, syms,
@@ -2611,6 +2619,10 @@  Symbol_table::set_dynsym_indexes(unsigned int index,
 	  ++index;
 	  syms->push_back(sym);
 	  dynpool->add(sym->name(), false, NULL);
+	  if (sym->type() == elfcpp::STT_GNU_IFUNC
+	      || (sym->binding() == elfcpp::STB_GNU_UNIQUE
+		  && parameters->options().gnu_unique()))
+	    this->set_has_gnu_output();
 
 	  // Record any version information, except those from
 	  // as-needed libraries not seen to be needed.  Note that the
@@ -2696,6 +2708,13 @@  Symbol_table::finalize(off_t off, off_t dynoff, size_t dyn_global_index,
   else
     gold_unreachable();
 
+  if (this->has_gnu_output_)
+    {
+      Target* target = const_cast<Target*>(&parameters->target());
+      if (target->osabi() == elfcpp::ELFOSABI_NONE)
+	target->set_osabi(elfcpp::ELFOSABI_GNU);
+    }
+
   // Now that we have the final symbol table, we can reliably note
   // which symbols should get warnings.
   this->warnings_.note_warnings(this);
@@ -2711,6 +2730,10 @@  void
 Symbol_table::add_to_final_symtab(Symbol* sym, Stringpool* pool,
 				  unsigned int* pindex, off_t* poff)
 {
+  if (sym->type() == elfcpp::STT_GNU_IFUNC
+      || (sym->binding() == elfcpp::STB_GNU_UNIQUE
+	  && parameters->options().gnu_unique()))
+    this->set_has_gnu_output();
   sym->set_symtab_index(*pindex);
   if (sym->version() == NULL || !parameters->options().relocatable())
     pool->add(sym->name(), false, NULL);
diff --git a/gold/symtab.h b/gold/symtab.h
index a9e8dd3278..dd931f5f04 100644
--- a/gold/symtab.h
+++ b/gold/symtab.h
@@ -1580,6 +1580,10 @@  class Symbol_table
   saw_undefined() const
   { return this->saw_undefined_; }
 
+  void
+  set_has_gnu_output()
+  { this->has_gnu_output_ = true; }
+
   // Allocate the common symbols
   void
   allocate_commons(Layout*, Mapfile*);
@@ -1981,6 +1985,8 @@  class Symbol_table
   // The number of global dynamic symbols (including forced-local symbols),
   // or 0 if none.
   unsigned int dynamic_count_;
+  // Set if a STT_GNU_IFUNC or STB_GNU_UNIQUE symbol will be output.
+  bool has_gnu_output_;
   // The symbol hash table.
   Symbol_table_type table_;
   // A pool of symbol names.  This is used for all global symbols.