diff options
Diffstat (limited to '0305-Backport-varasm-Handle-private-COMDAT-function-symbo.patch')
-rw-r--r-- | 0305-Backport-varasm-Handle-private-COMDAT-function-symbo.patch | 296 |
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 + |