297 lines
8.9 KiB
Diff
297 lines
8.9 KiB
Diff
|
|
From bbb4954294d010977fcfb96931384101cf015a44 Mon Sep 17 00:00:00 2001
|
||
|
|
From: Jakub Jelinek <jakub@redhat.com>
|
||
|
|
Date: Mon, 26 Feb 2024 17:55:07 +0100
|
||
|
|
Subject: [PATCH] [Backport]varasm: Handle private COMDAT function symbol
|
||
|
|
reference in readonly data section [PR113617]
|
||
|
|
|
||
|
|
If default_elf_select_rtx_section is called to put a reference to some
|
||
|
|
local symbol defined in a comdat section into memory, which happens more often
|
||
|
|
since the r14-4944 RA change, linking might fail.
|
||
|
|
default_elf_select_rtx_section puts such constants into .data.rel.ro.local
|
||
|
|
etc. sections and if linker chooses comdat sections from some other TU
|
||
|
|
and discards the one to which a relocation in .data.rel.ro.local remains,
|
||
|
|
linker diagnoses error. References to private comdat symbols can only appear
|
||
|
|
from functions or data objects in the same comdat group, so the following
|
||
|
|
patch arranges using .data.rel.ro.local.pool.<comdat_name> and similar sections.
|
||
|
|
|
||
|
|
2024-02-26 Jakub Jelinek <jakub@redhat.com>
|
||
|
|
H.J. Lu <hjl.tools@gmail.com>
|
||
|
|
|
||
|
|
PR rtl-optimization/113617
|
||
|
|
* varasm.cc (default_elf_select_rtx_section): For
|
||
|
|
references to private symbols in comdat sections
|
||
|
|
use .data.relro.local.pool.<comdat>, .data.relro.pool.<comdat>
|
||
|
|
or .rodata.<comdat> comdat sections.
|
||
|
|
|
||
|
|
* g++.dg/other/pr113617.C: New test.
|
||
|
|
* g++.dg/other/pr113617.h: New test.
|
||
|
|
* g++.dg/other/pr113617-aux.cc: New test.
|
||
|
|
---
|
||
|
|
gcc/testsuite/g++.dg/other/pr113617-aux.cc | 9 ++
|
||
|
|
gcc/testsuite/g++.dg/other/pr113617.C | 27 +++++
|
||
|
|
gcc/testsuite/g++.dg/other/pr113617.h | 132 +++++++++++++++++++++
|
||
|
|
gcc/varasm.cc | 48 +++++++-
|
||
|
|
4 files changed, 215 insertions(+), 1 deletion(-)
|
||
|
|
create mode 100644 gcc/testsuite/g++.dg/other/pr113617-aux.cc
|
||
|
|
create mode 100644 gcc/testsuite/g++.dg/other/pr113617.C
|
||
|
|
create mode 100644 gcc/testsuite/g++.dg/other/pr113617.h
|
||
|
|
|
||
|
|
diff --git a/gcc/testsuite/g++.dg/other/pr113617-aux.cc b/gcc/testsuite/g++.dg/other/pr113617-aux.cc
|
||
|
|
new file mode 100644
|
||
|
|
index 000000000..e6900e05a
|
||
|
|
--- /dev/null
|
||
|
|
+++ b/gcc/testsuite/g++.dg/other/pr113617-aux.cc
|
||
|
|
@@ -0,0 +1,9 @@
|
||
|
|
+// PR rtl-optimization/113617
|
||
|
|
+// { dg-do link { target { c++17 && c++14_down } } }
|
||
|
|
+
|
||
|
|
+#include "pr113617.h"
|
||
|
|
+
|
||
|
|
+void qux() {
|
||
|
|
+ A<long long> a;
|
||
|
|
+ a.foo(0, 0);
|
||
|
|
+}
|
||
|
|
diff --git a/gcc/testsuite/g++.dg/other/pr113617.C b/gcc/testsuite/g++.dg/other/pr113617.C
|
||
|
|
new file mode 100644
|
||
|
|
index 000000000..a02dda142
|
||
|
|
--- /dev/null
|
||
|
|
+++ b/gcc/testsuite/g++.dg/other/pr113617.C
|
||
|
|
@@ -0,0 +1,27 @@
|
||
|
|
+// PR rtl-optimization/113617
|
||
|
|
+// { dg-do link { target c++11 } }
|
||
|
|
+// { dg-options "-O2" }
|
||
|
|
+// { dg-additional-options "-fPIC" { target fpic } } */
|
||
|
|
+// { dg-additional-options "-shared" { target shared } } */
|
||
|
|
+// { dg-additional-sources pr113617-aux.cc }
|
||
|
|
+
|
||
|
|
+#include "pr113617.h"
|
||
|
|
+
|
||
|
|
+int z;
|
||
|
|
+long xx1;
|
||
|
|
+void corge() {
|
||
|
|
+ A<long long> a;
|
||
|
|
+ a.foo(xx1, 0);
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+typedef unsigned long int VV __attribute__((vector_size (2 * sizeof (long))));
|
||
|
|
+VV vv;
|
||
|
|
+__attribute__((noipa)) static void fn1 (void) {}
|
||
|
|
+__attribute__((noipa)) static void fn2 (void) {}
|
||
|
|
+
|
||
|
|
+void
|
||
|
|
+fn3 ()
|
||
|
|
+{
|
||
|
|
+ VV a = { (unsigned long) &fn1, (unsigned long) &fn2 };
|
||
|
|
+ vv = a;
|
||
|
|
+}
|
||
|
|
diff --git a/gcc/testsuite/g++.dg/other/pr113617.h b/gcc/testsuite/g++.dg/other/pr113617.h
|
||
|
|
new file mode 100644
|
||
|
|
index 000000000..4d30eddbc
|
||
|
|
--- /dev/null
|
||
|
|
+++ b/gcc/testsuite/g++.dg/other/pr113617.h
|
||
|
|
@@ -0,0 +1,132 @@
|
||
|
|
+namespace {
|
||
|
|
+template <int V> struct J { static constexpr int value = V; };
|
||
|
|
+template <bool V> using K = J<V>;
|
||
|
|
+using M = K<true>;
|
||
|
|
+template <int> struct L { template <typename _Tp, typename> using type = _Tp; };
|
||
|
|
+template <bool _Cond, typename _If, typename _Else> using N = typename L<_Cond>::type<_If, _Else>;
|
||
|
|
+M k;
|
||
|
|
+template <typename _Tp> struct O { using type = _Tp; };
|
||
|
|
+template <typename _Up>
|
||
|
|
+struct P : N<M ::value, O<_Up>, _Up> {};
|
||
|
|
+template <typename _Tp> struct Q { using type = typename P<_Tp>::type; };
|
||
|
|
+}
|
||
|
|
+namespace R {
|
||
|
|
+struct H;
|
||
|
|
+enum G {};
|
||
|
|
+template <typename> class S;
|
||
|
|
+struct T { using U = bool (*) (H &, const H &, G); U F; };
|
||
|
|
+template <typename, typename> class B;
|
||
|
|
+template <typename _R, typename _F, typename... _A>
|
||
|
|
+struct B<_R(_A...), _F> {
|
||
|
|
+ static bool F(H &, const H &, G) { return false; }
|
||
|
|
+ __attribute__((noipa)) static _R bar(const H &) {}
|
||
|
|
+};
|
||
|
|
+template <typename _R, typename... _A>
|
||
|
|
+struct S<_R(_A...)> : T {
|
||
|
|
+ template <typename _F> using AH = B<_R(), _F>;
|
||
|
|
+ template <typename _F> S(_F) {
|
||
|
|
+ using AG = AH<_F>;
|
||
|
|
+ barr = AG::bar;
|
||
|
|
+ F = AG::F;
|
||
|
|
+ }
|
||
|
|
+ using AF = _R (*)(const H &);
|
||
|
|
+ AF barr;
|
||
|
|
+};
|
||
|
|
+template <typename> class I;
|
||
|
|
+template <typename _F, typename... _B>
|
||
|
|
+struct I<_F(_B...)> {};
|
||
|
|
+template <typename> using W = decltype(k);
|
||
|
|
+template <int, typename _F, typename... _B> struct V {
|
||
|
|
+ typedef I<typename Q<_F>::type(typename Q<_B>::type...)> type;
|
||
|
|
+};
|
||
|
|
+template <typename _F, typename... _B>
|
||
|
|
+__attribute__((noipa)) typename V<W<_F>::value, _F, _B...>::type
|
||
|
|
+baz(_F, _B...) { return typename V<W<_F>::value, _F, _B...>::type (); }
|
||
|
|
+template <typename _Tp> struct AJ {
|
||
|
|
+ template <typename _Up> struct _Ptr { using type = _Up *; };
|
||
|
|
+ using AI = typename _Ptr<_Tp>::type;
|
||
|
|
+};
|
||
|
|
+template <typename _Tp> struct Y {
|
||
|
|
+ using AI = typename AJ<_Tp>::AI;
|
||
|
|
+ AI operator->();
|
||
|
|
+};
|
||
|
|
+}
|
||
|
|
+extern int z;
|
||
|
|
+namespace N1 {
|
||
|
|
+namespace N2 {
|
||
|
|
+namespace N3 {
|
||
|
|
+enum Z { Z1, Z2 };
|
||
|
|
+template <int> struct X {
|
||
|
|
+ template <typename _F>
|
||
|
|
+ __attribute__((noipa)) void boo(long long, long long, long long, _F &) {}
|
||
|
|
+};
|
||
|
|
+struct AC {
|
||
|
|
+ AC(int);
|
||
|
|
+ void m1(R::S<void()>);
|
||
|
|
+};
|
||
|
|
+template <typename>
|
||
|
|
+__attribute__((noipa)) void garply(void *, long long, long long, long long) {}
|
||
|
|
+template <>
|
||
|
|
+template <typename _F>
|
||
|
|
+void X<Z2>::boo(long long, long long x, long long y, _F &fi) {
|
||
|
|
+ AC pool(z);
|
||
|
|
+ for (;;) {
|
||
|
|
+ auto job = R::baz(garply<_F>, &fi, y, y, x);
|
||
|
|
+ pool.m1(job);
|
||
|
|
+ }
|
||
|
|
+}
|
||
|
|
+struct AB {
|
||
|
|
+ static AB &bleh();
|
||
|
|
+ template <typename _F>
|
||
|
|
+ void boo(long first, long x, long y, _F fi) {
|
||
|
|
+ switch (ab1) {
|
||
|
|
+ case Z1:
|
||
|
|
+ ab2->boo(first, x, y, fi);
|
||
|
|
+ case Z2:
|
||
|
|
+ ab3->boo(first, x, y, fi);
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ Z ab1;
|
||
|
|
+ R::Y<X<Z1>> ab2;
|
||
|
|
+ R::Y<X<Z2>> ab3;
|
||
|
|
+};
|
||
|
|
+template <typename, bool> struct C;
|
||
|
|
+template <typename _F> struct C<_F, false> {
|
||
|
|
+ __attribute__((noipa)) C(_F) {}
|
||
|
|
+ void boo(long first, long x, long y) {
|
||
|
|
+ auto u = AB::bleh();
|
||
|
|
+ u.boo(first, x, y, *this);
|
||
|
|
+ }
|
||
|
|
+};
|
||
|
|
+template <typename _F> struct AA { typedef C<_F, 0> type; };
|
||
|
|
+}
|
||
|
|
+}
|
||
|
|
+}
|
||
|
|
+struct AD {
|
||
|
|
+ template <typename _F>
|
||
|
|
+ static void boo(long first, long x, long y, _F f) {
|
||
|
|
+ typename N1::N2::N3::AA<_F>::type fi(f);
|
||
|
|
+ fi.boo(first, x, y);
|
||
|
|
+ }
|
||
|
|
+ template <typename _F>
|
||
|
|
+ static void boo(long first, long x, _F f) {
|
||
|
|
+ boo(first, x, 0, f);
|
||
|
|
+ }
|
||
|
|
+};
|
||
|
|
+template <typename> struct A {
|
||
|
|
+ void foo(long long, long long);
|
||
|
|
+ int *c;
|
||
|
|
+};
|
||
|
|
+namespace {
|
||
|
|
+template <typename> struct D { __attribute__((noipa)) D(int *) {} };
|
||
|
|
+}
|
||
|
|
+template <typename T>
|
||
|
|
+void A<T>::foo(long long x, long long y)
|
||
|
|
+{
|
||
|
|
+ int e;
|
||
|
|
+ D<T> d(&e);
|
||
|
|
+ AD::boo(0, y, d);
|
||
|
|
+ long p;
|
||
|
|
+ for (p = 0; p < x; p++)
|
||
|
|
+ c[p] = c[p - 1];
|
||
|
|
+}
|
||
|
|
diff --git a/gcc/varasm.cc b/gcc/varasm.cc
|
||
|
|
index bae935694..d122730b5 100644
|
||
|
|
--- a/gcc/varasm.cc
|
||
|
|
+++ b/gcc/varasm.cc
|
||
|
|
@@ -7317,17 +7317,63 @@ default_elf_select_rtx_section (machine_mode mode, rtx x,
|
||
|
|
unsigned HOST_WIDE_INT align)
|
||
|
|
{
|
||
|
|
int reloc = compute_reloc_for_rtx (x);
|
||
|
|
+ tree decl = nullptr;
|
||
|
|
+ const char *prefix = nullptr;
|
||
|
|
+ int flags = 0;
|
||
|
|
+
|
||
|
|
+ /* If it is a private COMDAT function symbol reference, call
|
||
|
|
+ function_rodata_section for the read-only or relocated read-only
|
||
|
|
+ data section associated with function DECL so that the COMDAT
|
||
|
|
+ section will be used for the private COMDAT function symbol. */
|
||
|
|
+ if (HAVE_COMDAT_GROUP)
|
||
|
|
+ {
|
||
|
|
+ if (GET_CODE (x) == CONST
|
||
|
|
+ && GET_CODE (XEXP (x, 0)) == PLUS
|
||
|
|
+ && CONST_INT_P (XEXP (XEXP (x, 0), 1)))
|
||
|
|
+ x = XEXP (XEXP (x, 0), 0);
|
||
|
|
+
|
||
|
|
+ if (GET_CODE (x) == SYMBOL_REF)
|
||
|
|
+ {
|
||
|
|
+ decl = SYMBOL_REF_DECL (x);
|
||
|
|
+ if (decl
|
||
|
|
+ && (TREE_CODE (decl) != FUNCTION_DECL
|
||
|
|
+ || !DECL_COMDAT_GROUP (decl)
|
||
|
|
+ || TREE_PUBLIC (decl)))
|
||
|
|
+ decl = nullptr;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
|
||
|
|
/* ??? Handle small data here somehow. */
|
||
|
|
|
||
|
|
if (reloc & targetm.asm_out.reloc_rw_mask ())
|
||
|
|
{
|
||
|
|
- if (reloc == 1)
|
||
|
|
+ if (decl)
|
||
|
|
+ {
|
||
|
|
+ prefix = reloc == 1 ? ".data.rel.ro.local" : ".data.rel.ro";
|
||
|
|
+ flags = SECTION_WRITE | SECTION_RELRO;
|
||
|
|
+ }
|
||
|
|
+ else if (reloc == 1)
|
||
|
|
return get_named_section (NULL, ".data.rel.ro.local", 1);
|
||
|
|
else
|
||
|
|
return get_named_section (NULL, ".data.rel.ro", 3);
|
||
|
|
}
|
||
|
|
|
||
|
|
+ if (decl)
|
||
|
|
+ {
|
||
|
|
+ const char *comdat = IDENTIFIER_POINTER (DECL_COMDAT_GROUP (decl));
|
||
|
|
+ if (!prefix)
|
||
|
|
+ prefix = ".rodata";
|
||
|
|
+ size_t prefix_len = strlen (prefix);
|
||
|
|
+ size_t comdat_len = strlen (comdat);
|
||
|
|
+ size_t len = prefix_len + sizeof (".pool.") + comdat_len;
|
||
|
|
+ char *name = XALLOCAVEC (char, len);
|
||
|
|
+ memcpy (name, prefix, prefix_len);
|
||
|
|
+ memcpy (name + prefix_len, ".pool.", sizeof (".pool.") - 1);
|
||
|
|
+ memcpy (name + prefix_len + sizeof (".pool.") - 1, comdat,
|
||
|
|
+ comdat_len + 1);
|
||
|
|
+ return get_section (name, flags | SECTION_LINKONCE, decl);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
return mergeable_constant_section (mode, align, 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
--
|
||
|
|
2.33.0
|
||
|
|
|