aboutsummaryrefslogtreecommitdiff
path: root/gold
diff options
context:
space:
mode:
Diffstat (limited to 'gold')
-rw-r--r--gold/ChangeLog11
-rw-r--r--gold/i386.cc15
-rw-r--r--gold/testsuite/protected_1.cc25
-rw-r--r--gold/testsuite/protected_main_1.cc4
-rw-r--r--gold/x86_64.cc15
5 files changed, 70 insertions, 0 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog
index 3dc9723..d4b8bc3 100644
--- a/gold/ChangeLog
+++ b/gold/ChangeLog
@@ -1,3 +1,14 @@
+2011-07-12 Ian Lance Taylor <iant@google.com>
+
+ PR gold/12980
+ * i386.cc (Target_i386::Scan::global): For a GOT reloc, use a
+ GLOB_DAT relocation rather than a RELATIVE relocation for a
+ protected symbol when creating a shared library.
+ * x86_64.cc (Target_x86_64::Scan::global): Likewise.
+ * testsuite/protected_1.cc (f2, get_f2_addr): New functions.
+ * testsuite/protected_main_1.cc (main): Test that protected
+ function has same address.
+
2011-07-11 Ian Lance Taylor <iant@google.com>
PR gold/12979
diff --git a/gold/i386.cc b/gold/i386.cc
index 8d3b630..84b9f07 100644
--- a/gold/i386.cc
+++ b/gold/i386.cc
@@ -1985,9 +1985,24 @@ Target_i386::Scan::global(Symbol_table* symtab,
// If this symbol is not fully resolved, we need to add a
// GOT entry with a dynamic relocation.
Reloc_section* rel_dyn = target->rel_dyn_section(layout);
+
+ // Use a GLOB_DAT rather than a RELATIVE reloc if:
+ //
+ // 1) The symbol may be defined in some other module.
+ //
+ // 2) We are building a shared library and this is a
+ // protected symbol; using GLOB_DAT means that the dynamic
+ // linker can use the address of the PLT in the main
+ // executable when appropriate so that function address
+ // comparisons work.
+ //
+ // 3) This is a STT_GNU_IFUNC symbol in position dependent
+ // code, again so that function address comparisons work.
if (gsym->is_from_dynobj()
|| gsym->is_undefined()
|| gsym->is_preemptible()
+ || (gsym->visibility() == elfcpp::STV_PROTECTED
+ && parameters->options().shared())
|| (gsym->type() == elfcpp::STT_GNU_IFUNC
&& parameters->options().output_is_position_independent()))
got->add_global_with_rel(gsym, GOT_TYPE_STANDARD,
diff --git a/gold/testsuite/protected_1.cc b/gold/testsuite/protected_1.cc
index 9183312..049bda7 100644
--- a/gold/testsuite/protected_1.cc
+++ b/gold/testsuite/protected_1.cc
@@ -31,3 +31,28 @@ f1()
{
return 1;
}
+
+// The function f2 is used to test that the executable can see the
+// same function address for a protected function in the executable
+// and in the shared library. We can't use the visibility attribute
+// here, becaues that may cause gcc to generate a PC relative reloc;
+// we need it to get the value from the GOT. I'm not sure this is
+// really useful, given that it doesn't work with the visibility
+// attribute. This test exists here mainly because the glibc
+// testsuite has the same test, and we want to make sure that gold
+// passes the glibc testsuite.
+
+extern "C" int f2();
+asm(".protected f2");
+
+extern "C" int
+f2()
+{
+ return 2;
+}
+
+int
+(*get_f2_addr())()
+{
+ return f2;
+}
diff --git a/gold/testsuite/protected_main_1.cc b/gold/testsuite/protected_main_1.cc
index cc387a4..271446f 100644
--- a/gold/testsuite/protected_main_1.cc
+++ b/gold/testsuite/protected_main_1.cc
@@ -28,9 +28,13 @@
extern bool t1();
extern bool t2();
+extern "C" int f2();
+extern int (*get_f2_addr()) ();
+
int
main()
{
assert(t1());
assert(t2());
+ assert(&f2 == get_f2_addr());
}
diff --git a/gold/x86_64.cc b/gold/x86_64.cc
index de204cb..ef66737 100644
--- a/gold/x86_64.cc
+++ b/gold/x86_64.cc
@@ -2436,9 +2436,24 @@ Target_x86_64::Scan::global(Symbol_table* symtab,
// If this symbol is not fully resolved, we need to add a
// dynamic relocation for it.
Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+
+ // Use a GLOB_DAT rather than a RELATIVE reloc if:
+ //
+ // 1) The symbol may be defined in some other module.
+ //
+ // 2) We are building a shared library and this is a
+ // protected symbol; using GLOB_DAT means that the dynamic
+ // linker can use the address of the PLT in the main
+ // executable when appropriate so that function address
+ // comparisons work.
+ //
+ // 3) This is a STT_GNU_IFUNC symbol in position dependent
+ // code, again so that function address comparisons work.
if (gsym->is_from_dynobj()
|| gsym->is_undefined()
|| gsym->is_preemptible()
+ || (gsym->visibility() == elfcpp::STV_PROTECTED
+ && parameters->options().shared())
|| (gsym->type() == elfcpp::STT_GNU_IFUNC
&& parameters->options().output_is_position_independent()))
got->add_global_with_rela(gsym, GOT_TYPE_STANDARD, rela_dyn,