I'm trying to put a specific set of functions into a separate section and got trouble doing it with GCC.
namespace /* anonymous */ {
[[gnu::section(".mysection")]]
void regular_func() { }
template <class T>
[[gnu::section(".mysection")]]
void template_func() { }
} // namespace /* anonymous */
void (*ptr1)() = ®ular_func;
void (*ptr2)() = &template_func<int>;
With clang, the symbols for both of regular_func
and template_func<int>
are placed in .mysection
as I expected.
$ clang++ -std=c++14 a.cpp -c && objdump -t a.o | grep -E "regular|template"
0000000000000000 l F .mysection 0000000000000006 _ZN12_GLOBAL__N_112regular_funcEv
0000000000000010 l F .mysection 0000000000000006 _ZN12_GLOBAL__N_113template_funcIiEEvv
But with GCC, the function template is not placed in .mysection
, but in the .text.*
section.
$ g++ -std=c++14 a.cpp -c && objdump -t a.o | grep -E "regular|template"
0000000000000000 l F .mysection 0000000000000007 _ZN12_GLOBAL__N_112regular_funcEv
0000000000000000 l F .text 0000000000000007 _ZN12_GLOBAL__N_113template_funcIiEEvv
I'm using clang-3.7.1 and gcc-5.3.0.
How can I force gcc to put the template-instantiated function in a separate section?
It may be small comfort, but GCC will oblige if you apply the section
attribute to an explicit instantiation of template <class T> void template_func()
,
for each T
that you want to be instantiated, e.g.
namespace /* anonymous */ {
[[gnu::section(".mysection")]]
void regular_func() { }
template <class T>
void template_func() { }
template [[gnu::section(".mysection")]] void template_func<int>();
} // namespace /* anonymous */
void (*ptr1)() = ®ular_func;
void (*ptr2)() = &template_func<int>;
Then:
$ g++ -std=c++14 a.cpp -c && objdump -C -t a.o | grep -E "regular|template"
0000000000000000 l F .mysection 0000000000000007 (anonymous namespace)::regular_func()
0000000000000007 l F .mysection 0000000000000007 void (anonymous namespace)::template_func<int>()
Unfortunately clang rejects:
template [[gnu::section(".mysection")]] void template_func<int>();
saying:
template [[gnu::section(".mysection")]] void template_func<int>();
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: an attribute list cannot appear here
so each compiler must have its own way, via conditional compilation.
Moreover this fix brings the added headache that you must somehow ensure
that template_func()
can't be instantated for any T
that you haven't explicitly
instantiated.
You may achieve that by statically asserting in the function template's body that
T
is one of types A,B,C...
that you allow to be instantiated. Then if it
is ever instantiated with T
= D
, the static_assert
will fire; you can
add D
to the list and add an explicit instantiation for D
:
#include <type_traits>
template<typename T, typename First>
constexpr bool is_in()
{
return std::is_same<T,First>::value;
}
template<typename T, typename First, typename Second, typename ...Rest>
constexpr bool is_in()
{
return is_in<T,First>() || is_in<T,Second,Rest...>();
}
namespace /* anonymous */ {
[[gnu::section(".mysection")]]
void regular_func() { }
template <class T>
void template_func()
{
static_assert(is_in<T,int,float>(),"");
}
template [[gnu::section(".mysection")]] void template_func<int>();
template [[gnu::section(".mysection")]] void template_func<float>();
} // namespace /* anonymous */
void (*ptr1)() = ®ular_func;
void (*ptr2)() = &template_func<int>;
void (*ptr3)() = &template_func<float>;
void (*ptr4)() = &template_func<char>; // <-- static_assert fails
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With