Linker plugins should be aware of --defsym during symbol resolution

Sriraman Tallam via binutils binutils@sourceware.org
Wed Feb 14 01:05:00 GMT 2018


New patch attached with all changes made.

gold/
* expression.cc (Symbol_expression::set_expr_sym_in_real_elf):
      New method.
(Unary_expression::set_expr_sym_in_real_elf): New method.
(Binary_expression::set_expr_sym_in_real_elf): New method.
(Trinary_expression::set_expr_sym_in_real_elf): New method.
* plugin.cc (get_symbol_resolution_info): Fix symbol resolution if
defined or used in defsyms.
* script.cc (set_defsym_uses_in_real_elf): New method.
(Script_options::is_defsym_def): New method.
* script.h (Expression::set_expr_sym_in_real_elf): New method.
(Symbol_assignment::is_defsym): New method.
(Symbol_assignment::value): New method.
(Script_options::is_defsym_def): New method.
(Script_options::set_defsym_uses_in_real_elf): New method.

On Tue, Feb 13, 2018 at 5:03 PM, Sriraman Tallam <tmsriram@google.com> wrote:
>
>
> On Tue, Feb 13, 2018 at 4:52 PM, Sriraman Tallam <tmsriram@google.com>
> wrote:
>>
>>
>>
>> On Tue, Feb 13, 2018 at 4:49 PM, Teresa Johnson <tejohnson@google.com>
>> wrote:
>>>
>>>
>>>
>>> On Tue, Feb 13, 2018 at 4:04 PM, Cary Coutant <ccoutant@gmail.com> wrote:
>>>>
>>>> >> Do you have a real-world example? I'm having trouble imagining a case
>>>> >> where --defsym would be used to override a symbol that's subject to
>>>> >> the ODR and yet remain a valid program.
>>>> >
>>>> > I just concocted one:
>>>> > ...
>>>> > With defsym:
>>>> >
>>>> > $ ~/llvm/llvm_8_build/bin/clang++ hello[12].cc  -fuse-ld=gold
>>>> > -Wl,--defsym,_Z3barv=_Z3bazv
>>>>
>>>> To me, this is the same as providing an overriding definition of bar()
>>>> that prints "in baz", which clearly violates the one-definition rule.
>>>>
>>>> On what basis do you consider this a valid thing to do, to the extent
>>>> that you want to preserve the unoptimized behavior across LTO?
>>>>
>>>> Is there a real-world example where someone would want to do this in
>>>> production code? I'm afraid I'd have zero sympathy for them. If they
>>>> want something like that to work, they should just turn off
>>>> cross-module inlining.
>>>
>>>
>>> Fair enough. It was a contrived example, not based on anything I have
>>> seen so far. If that violates ODR then I agree all bets are off.
>>>
>>> Let me try with a modified change that marks these with
>>> LDPR_PREEMPTED_REG. Sri, would you mind changing the patch and I'll give the
>>> new version a try?
>
>
>
> New patch attached.
>
>
> gold/
> * expression.cc (Symbol_expression::set_expr_sym_in_real_elf):
>       New method.
> (Unary_expression::set_expr_sym_in_real_elf): New method.
> (Binary_expression::set_expr_sym_in_real_elf): New method.
> (Trinary_expression::set_expr_sym_in_real_elf): New method.
> * plugin.cc (get_symbol_resolution_info): Fix symbol resolution if
> defined or used in defsyms.
> * script.cc (set_defsym_uses_in_real_elf): New method.
> (Script_options::is_defsym_def): New method.
> * script.h (Expression::set_expr_sym_in_real_elf): New method.
> (Symbol_assignment::is_defsym): New method.
> (Symbol_assignment::value): New method.
> (Script_options::is_defsym_def): New method.
> (Script_options::set_defsym_uses_in_real_elf): New method.
> * testsuite/Makefile.am (plugin_test_defsym): New test.
> * testsuite/Makefile.in: Regenerate.
> * testsuite/plugin_test.c: Check for new symbol resolution.
> * testsuite/plugin_test_defsym.sh: New script.
> * testsuite/plugin_test_defsym.c: New test source.
>
>
>
>>
>>
>> No problem.
>>
>>>
>>>
>>> Thanks,
>>> Teresa
>>>
>>>>
>>>> I need a lot more justification to extend the plugin API.
>>>>
>>>> -cary
>>>
>>>
>>>
>>>
>>> --
>>> Teresa Johnson | Software Engineer | tejohnson@google.com | 408-460-2413
>>
>>
>
-------------- next part --------------
	gold/
	* expression.cc (Symbol_expression::set_expr_sym_in_real_elf):
      	New method.
	(Unary_expression::set_expr_sym_in_real_elf): New method.
	(Binary_expression::set_expr_sym_in_real_elf): New method.
	(Trinary_expression::set_expr_sym_in_real_elf): New method.
	* plugin.cc (get_symbol_resolution_info): Fix symbol resolution if
	defined or used in defsyms.
	* script.cc (set_defsym_uses_in_real_elf): New method.
	(Script_options::is_defsym_def): New method.
	* script.h (Expression::set_expr_sym_in_real_elf): New method.
	(Symbol_assignment::is_defsym): New method.
	(Symbol_assignment::value): New method.
	(Script_options::is_defsym_def): New method.
	(Script_options::set_defsym_uses_in_real_elf): New method.
	* testsuite/Makefile.am (plugin_test_defsym): New test.
	* testsuite/Makefile.in: Regenerate.
	* testsuite/plugin_test.c: Check for new symbol resolution.
	* testsuite/plugin_test_defsym.sh: New script.
	* testsuite/plugin_test_defsym.c: New test source.
	
diff --git a/gold/expression.cc b/gold/expression.cc
index d764cc2a9d..ff807756b9 100644
--- a/gold/expression.cc
+++ b/gold/expression.cc
@@ -205,6 +205,13 @@ class Symbol_expression : public Expression
   uint64_t
   value(const Expression_eval_info*);
 
+  void
+  set_expr_sym_in_real_elf(Symbol_table* symtab) const
+  {
+    Symbol* sym = symtab->lookup(this->name_.c_str());
+    sym->set_in_real_elf();
+  }
+
   void
   print(FILE* f) const
   { fprintf(f, "%s", this->name_.c_str()); }
@@ -318,6 +325,10 @@ class Unary_expression : public Expression
   arg_print(FILE* f) const
   { this->arg_->print(f); }
 
+  void
+  set_expr_sym_in_real_elf(Symbol_table* symtab) const
+  { return this->arg_->set_expr_sym_in_real_elf(symtab); }
+
  private:
   Expression* arg_;
 };
@@ -437,6 +448,13 @@ class Binary_expression : public Expression
     fprintf(f, ")");
   }
 
+  void
+  set_expr_sym_in_real_elf(Symbol_table* symtab) const
+  {
+    this->left_->set_expr_sym_in_real_elf(symtab);
+    this->right_->set_expr_sym_in_real_elf(symtab);
+  }
+
  private:
   Expression* left_;
   Expression* right_;
@@ -622,6 +640,14 @@ class Trinary_expression : public Expression
   arg3_print(FILE* f) const
   { this->arg3_->print(f); }
 
+  void
+  set_expr_sym_in_real_elf(Symbol_table* symtab) const
+  {
+    this->arg1_->set_expr_sym_in_real_elf(symtab);
+    this->arg2_->set_expr_sym_in_real_elf(symtab);
+    this->arg3_->set_expr_sym_in_real_elf(symtab);
+  }
+
  private:
   Expression* arg1_;
   Expression* arg2_;
diff --git a/gold/plugin.cc b/gold/plugin.cc
index 02fef25dda..9c14b22c40 100644
--- a/gold/plugin.cc
+++ b/gold/plugin.cc
@@ -989,6 +989,9 @@ Pluginobj::get_symbol_resolution_info(Symbol_table* symtab,
       return version > 2 ? LDPS_NO_SYMS : LDPS_OK;
     }
 
+  Layout *layout = parameters->options().plugins()->layout();
+  layout->script_options()->set_defsym_uses_in_real_elf(symtab);
+
   for (int i = 0; i < nsyms; i++)
     {
       ld_plugin_symbol* isym = &syms[i];
@@ -997,9 +1000,16 @@ Pluginobj::get_symbol_resolution_info(Symbol_table* symtab,
         lsym = symtab->resolve_forwards(lsym);
       ld_plugin_symbol_resolution res = LDPR_UNKNOWN;
 
-      if (lsym->is_undefined())
-        // The symbol remains undefined.
-        res = LDPR_UNDEF;
+      if (layout->script_options()->is_defsym_def(lsym->name()))
+	{
+	  // The symbol is redefined via defsym.
+	  res = LDPR_PREEMPTED_REG;
+	}
+      else if (lsym->is_undefined())
+	{
+            // The symbol remains undefined.
+            res = LDPR_UNDEF;
+	}
       else if (isym->def == LDPK_UNDEF
                || isym->def == LDPK_WEAKUNDEF
                || isym->def == LDPK_COMMON)
diff --git a/gold/script.cc b/gold/script.cc
index db243cf435..8aac6e97b2 100644
--- a/gold/script.cc
+++ b/gold/script.cc
@@ -1112,6 +1112,30 @@ Script_options::is_pending_assignment(const char* name)
   return false;
 }
 
+// Returns true if symbol with NAME is redefined by defsym.
+
+bool Script_options::is_defsym_def(const char* name) const
+{
+  for (Symbol_assignments::const_iterator p = this->symbol_assignments_.begin();
+       p != this->symbol_assignments_.end();
+       ++p)
+    if ((*p)->is_defsym() && (*p)->name() == name)
+      return true;
+  return false;
+}
+
+void
+Script_options::set_defsym_uses_in_real_elf(Symbol_table* symtab) const
+{
+  for (Symbol_assignments::const_iterator p = this->symbol_assignments_.begin();
+       p != this->symbol_assignments_.end();
+       ++p)
+    {
+      if ((*p)->is_defsym())
+        (*p)->value()->set_expr_sym_in_real_elf(symtab);
+    }
+}
+
 // Add a symbol to be defined.
 
 void
diff --git a/gold/script.h b/gold/script.h
index ec8ce8e110..46bad76888 100644
--- a/gold/script.h
+++ b/gold/script.h
@@ -129,13 +129,17 @@ class Expression
   virtual uint64_t
   value(const Expression_eval_info*) = 0;
 
+  // Sets all symbols used in expressions as seen in a real ELF object.
+  virtual void
+  set_expr_sym_in_real_elf(Symbol_table*) const
+  { return; }
+
  private:
   // May not be copied.
   Expression(const Expression&);
   Expression& operator=(const Expression&);
 };
 
-
 // Version_script_info stores information parsed from the version
 // script, either provided by --version-script or as part of a linker
 // script.  A single Version_script_info object per target is owned by
@@ -344,6 +348,14 @@ class Symbol_assignment
   void
   finalize(Symbol_table*, const Layout*);
 
+  bool
+  is_defsym() const
+  { return is_defsym_; }
+
+  Expression *
+  value() const
+  { return val_; }
+
   // Finalize the symbol value when it can refer to the dot symbol.
   void
   finalize_with_dot(Symbol_table*, const Layout*, uint64_t dot_value,
@@ -454,6 +466,13 @@ class Script_options
   bool
   define_symbol(const char* definition);
 
+  // Returns true if symbol is defined via defsym.
+  bool
+  is_defsym_def(const char *name) const;
+
+  // Set symbols used in defsym expressions as seen in a real ELF object.
+  void set_defsym_uses_in_real_elf(Symbol_table*) const;
+
   // Create sections required by any linker scripts.
   void
   create_script_sections(Layout*);
diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am
index 16cae8004c..7ec3e8d88f 100644
--- a/gold/testsuite/Makefile.am
+++ b/gold/testsuite/Makefile.am
@@ -2332,11 +2332,22 @@ plugin_test_start_lib: unused.o plugin_start_lib_test.o plugin_start_lib_test_2.
 plugin_test_start_lib.err: plugin_test_start_lib
 	@touch plugin_test_start_lib.err
 
+check_PROGRAMS += plugin_test_defsym
+check_SCRIPTS += plugin_test_defsym.sh
+check_DATA += plugin_test_defsym.err
+MOSTLYCLEANFILES += plugin_test_defsym.err
+plugin_test_defsym.syms: plugin_test_defsym.o
+	$(TEST_READELF) -sW $< >$@ 2>/dev/null
+plugin_test_defsym.o: plugin_test_defsym.c
+	$(COMPILE) -c -o $@ $<
+plugin_test_defsym: plugin_test_defsym.o plugin_test_defsym.syms gcctestdir/ld plugin_test.so
+	$(CXXLINK) -Bgcctestdir/ -Wl,--no-demangle,--plugin,"./plugin_test.so" -Wl,--defsym,bar=foo plugin_test_defsym.syms 2>plugin_test_defsym.err
+plugin_test_defsym.err: plugin_test_defsym
+	@touch plugin_test_defsym.err
 
 plugin_start_lib_test_2.syms: plugin_start_lib_test_2.o
 	$(TEST_READELF) -sW $< >$@ 2>/dev/null
 
-
 plugin_test.so: plugin_test.o gcctestdir/ld
 	$(LINK) -Bgcctestdir/ -shared plugin_test.o
 plugin_test.o: plugin_test.c
diff --git a/gold/testsuite/plugin_test_defsym.c b/gold/testsuite/plugin_test_defsym.c
index e69de29bb2..a3c3b962f3 100644
--- a/gold/testsuite/plugin_test_defsym.c
+++ b/gold/testsuite/plugin_test_defsym.c
@@ -0,0 +1,32 @@
+/* plugin_test_defsym.c -- a test case for gold
+
+   Copyright (C) 2018 onwards Free Software Foundation, Inc.
+   Written by Sriraman Tallam <tmsriram@google.com>
+
+   This file is part of gold.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+int foo(void);
+int foo(void) {
+  return 0;
+}
+
+int bar(void);
+
+int main(void) {
+  return bar();  
+}
diff --git a/gold/testsuite/plugin_test_defsym.sh b/gold/testsuite/plugin_test_defsym.sh
index e69de29bb2..6066f9b0c9 100755
--- a/gold/testsuite/plugin_test_defsym.sh
+++ b/gold/testsuite/plugin_test_defsym.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+
+# plugin_test_defsym.sh -- a test case for the plugin API.
+
+# Copyright (C) 2018 onwards Free Software Foundation, Inc.
+# Written by Sriraman Tallam <tmsriram@google.com>.
+
+# This file is part of gold.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+# This file goes with plugin_test.c, a simple plug-in library that
+# exercises the basic interfaces and prints out version numbers and
+# options passed to the plugin.
+
+# This checks if the symbol resolution withe export dynamic symbol is
+# as expected.
+
+check()
+{
+    if ! grep -q "$2" "$1"
+    then
+	echo "Did not find expected output in $1:"
+	echo "   $2"
+	echo ""
+	echo "Actual output below:"
+	cat "$1"
+	exit 1
+    fi
+}
+
+check plugin_test_defsym.err "API version:"
+check plugin_test_defsym.err "gold version:"
+check plugin_test_defsym.err "plugin_test_defsym.syms: claim file hook called"
+check plugin_test_defsym.err "plugin_test_defsym.syms: bar: PREEMPTED_REG"
+check plugin_test_defsym.err "plugin_test_defsym.syms: foo: PREVAILING_DEF_REG"
+check plugin_test_defsym.err "cleanup hook called"
+
+exit 0


More information about the Binutils mailing list