Linker plugins should be aware of --defsym during symbol resolution
Sriraman Tallam via binutils
binutils@sourceware.org
Wed Feb 14 20:57:00 GMT 2018
New patch attached.
* 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.
* plugin.h (Plugin_manager::is_defsym_def): New method.
(Plugin_manager::Plugin_manager): Initialize defsym_defines_set_.
(Plugin_manager::defsym_defines_set_): New member.
(Plugin_manager::Defsym_defines_set): New typedef.
* script.cc (Script_options::set_defsym_uses_in_real_elf): New method.
(Script_options::find_defsym_defs): 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::find_defsym_defs): 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.
On Wed, Feb 14, 2018 at 10:29 AM, Sriraman Tallam <tmsriram@google.com> wrote:
> On Tue, Feb 13, 2018 at 10:14 PM, Cary Coutant <ccoutant@gmail.com> wrote:
>> + void
>> + set_expr_sym_in_real_elf(Symbol_table* symtab) const
>> + {
>> + Symbol* sym = symtab->lookup(this->name_.c_str());
>> + sym->set_in_real_elf();
>> + }
>>
>> Since you pointed out that this is running before
>> define_script_symbols(), I now realize that some of these symbols
>> might not be in the symbol table, and Symbol_table::lookup() can
>> return NULL. I think if that's the case, though, the symbol is not
>> referenced from IR, so it is unimportant, and you can just ignore
>> trying to set the in_real_elf flag if sym == NULL. Agreed?
>
> Yes, thanks for pointing this out. Will make that change, thanks!
>
>>
>> -cary
>>
>>
>>
>> On Tue, Feb 13, 2018 at 5:05 PM, Sriraman Tallam <tmsriram@google.com> wrote:
>>> 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 --------------
* 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.
* plugin.h (Plugin_manager::is_defsym_def): New method.
(Plugin_manager::Plugin_manager): Initialize defsym_defines_set_.
(Plugin_manager::defsym_defines_set_): New member.
(Plugin_manager::Defsym_defines_set): New typedef.
* script.cc (Script_options::set_defsym_uses_in_real_elf): New method.
(Script_options::find_defsym_defs): 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::find_defsym_defs): 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..bbfaa1ee16 100644
--- a/gold/expression.cc
+++ b/gold/expression.cc
@@ -205,6 +205,14 @@ 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());
+ if (sym != NULL)
+ sym->set_in_real_elf();
+ }
+
void
print(FILE* f) const
{ fprintf(f, "%s", this->name_.c_str()); }
@@ -318,6 +326,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 +449,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 +641,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..566f1b7cae 100644
--- a/gold/plugin.cc
+++ b/gold/plugin.cc
@@ -580,6 +580,11 @@ Plugin_manager::all_symbols_read(Workqueue* workqueue, Task* task,
this->mapfile_ = mapfile;
this->this_blocker_ = NULL;
+ // Set symbols used in defsym expressions as seen in real ELF.
+ Layout *layout = parameters->options().plugins()->layout();
+ layout->script_options()->set_defsym_uses_in_real_elf(symtab);
+ layout->script_options()->find_defsym_defs(this->defsym_defines_set_);
+
for (this->current_ = this->plugins_.begin();
this->current_ != this->plugins_.end();
++this->current_)
@@ -989,6 +994,7 @@ Pluginobj::get_symbol_resolution_info(Symbol_table* symtab,
return version > 2 ? LDPS_NO_SYMS : LDPS_OK;
}
+ Plugin_manager* plugins = parameters->options().plugins();
for (int i = 0; i < nsyms; i++)
{
ld_plugin_symbol* isym = &syms[i];
@@ -997,9 +1003,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 (plugins->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/plugin.h b/gold/plugin.h
index db6093daa7..e64ee07bb6 100644
--- a/gold/plugin.h
+++ b/gold/plugin.h
@@ -146,11 +146,18 @@ class Plugin_manager
options_(options), workqueue_(NULL), task_(NULL), input_objects_(NULL),
symtab_(NULL), layout_(NULL), dirpath_(NULL), mapfile_(NULL),
this_blocker_(NULL), extra_search_path_(), lock_(NULL),
- initialize_lock_(&lock_)
+ initialize_lock_(&lock_), defsym_defines_set_()
{ this->current_ = plugins_.end(); }
~Plugin_manager();
+ // Returns true if the symbol name is used in the LHS of a defsym.
+ bool
+ is_defsym_def(const char* sym_name) const
+ {
+ return defsym_defines_set_.find(sym_name) != defsym_defines_set_.end();
+ }
+
// Add a plugin library.
void
add_plugin(const char* filename)
@@ -402,6 +409,10 @@ class Plugin_manager
std::string extra_search_path_;
Lock* lock_;
Initialize_lock initialize_lock_;
+
+ // Keep track of all symbols defined by defsym.
+ typedef Unordered_set<std::string> Defsym_defines_set;
+ Defsym_defines_set defsym_defines_set_;
};
diff --git a/gold/script.cc b/gold/script.cc
index db243cf435..75b877daa2 100644
--- a/gold/script.cc
+++ b/gold/script.cc
@@ -1112,6 +1112,31 @@ Script_options::is_pending_assignment(const char* name)
return false;
}
+// Populates the set with symbols used in defsym LHS.
+
+void Script_options::find_defsym_defs(Unordered_set<std::string>& defsym_set)
+{
+ for (Symbol_assignments::const_iterator p = this->symbol_assignments_.begin();
+ p != this->symbol_assignments_.end();
+ ++p)
+ {
+ if ((*p)->is_defsym())
+ defsym_set.insert((*p)->name());
+ }
+}
+
+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..aaf825a786 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);
+ // Populates the set with symbol names used in LHS of defsym.
+ void
+ find_defsym_defs(Unordered_set<std::string>&);
+
+ // 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..3b004c6520 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