summaryrefslogtreecommitdiff
path: root/0305-Backport-varasm-Handle-private-COMDAT-function-symbo.patch
diff options
context:
space:
mode:
Diffstat (limited to '0305-Backport-varasm-Handle-private-COMDAT-function-symbo.patch')
-rw-r--r--0305-Backport-varasm-Handle-private-COMDAT-function-symbo.patch296
1 files changed, 296 insertions, 0 deletions
diff --git a/0305-Backport-varasm-Handle-private-COMDAT-function-symbo.patch b/0305-Backport-varasm-Handle-private-COMDAT-function-symbo.patch
new file mode 100644
index 0000000..e3bf4dc
--- /dev/null
+++ b/0305-Backport-varasm-Handle-private-COMDAT-function-symbo.patch
@@ -0,0 +1,296 @@
+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
+