From bbb4954294d010977fcfb96931384101cf015a44 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek 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. and similar sections. 2024-02-26 Jakub Jelinek H.J. Lu PR rtl-optimization/113617 * varasm.cc (default_elf_select_rtx_section): For references to private symbols in comdat sections use .data.relro.local.pool., .data.relro.pool. or .rodata. 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 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 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 struct J { static constexpr int value = V; }; +template using K = J; +using M = K; +template struct L { template using type = _Tp; }; +template using N = typename L<_Cond>::type<_If, _Else>; +M k; +template struct O { using type = _Tp; }; +template +struct P : N, _Up> {}; +template struct Q { using type = typename P<_Tp>::type; }; +} +namespace R { +struct H; +enum G {}; +template class S; +struct T { using U = bool (*) (H &, const H &, G); U F; }; +template class B; +template +struct B<_R(_A...), _F> { + static bool F(H &, const H &, G) { return false; } + __attribute__((noipa)) static _R bar(const H &) {} +}; +template +struct S<_R(_A...)> : T { + template using AH = B<_R(), _F>; + template S(_F) { + using AG = AH<_F>; + barr = AG::bar; + F = AG::F; + } + using AF = _R (*)(const H &); + AF barr; +}; +template class I; +template +struct I<_F(_B...)> {}; +template using W = decltype(k); +template struct V { + typedef I::type(typename Q<_B>::type...)> type; +}; +template +__attribute__((noipa)) typename V::value, _F, _B...>::type +baz(_F, _B...) { return typename V::value, _F, _B...>::type (); } +template struct AJ { + template struct _Ptr { using type = _Up *; }; + using AI = typename _Ptr<_Tp>::type; +}; +template struct Y { + using AI = typename AJ<_Tp>::AI; + AI operator->(); +}; +} +extern int z; +namespace N1 { +namespace N2 { +namespace N3 { +enum Z { Z1, Z2 }; +template struct X { + template + __attribute__((noipa)) void boo(long long, long long, long long, _F &) {} +}; +struct AC { + AC(int); + void m1(R::S); +}; +template +__attribute__((noipa)) void garply(void *, long long, long long, long long) {} +template <> +template +void X::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 + 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> ab2; + R::Y> ab3; +}; +template struct C; +template 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 struct AA { typedef C<_F, 0> type; }; +} +} +} +struct AD { + template + 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 + static void boo(long first, long x, _F f) { + boo(first, x, 0, f); + } +}; +template struct A { + void foo(long long, long long); + int *c; +}; +namespace { +template struct D { __attribute__((noipa)) D(int *) {} }; +} +template +void A::foo(long long x, long long y) +{ + int e; + D 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