The function template section attribute is silently ignored in GCC

I am trying to put a specific set of functions in a separate section and got problems with GCC.

namespace /* anonymous */ { [[gnu::section(".mysection")]] void regular_func() { } template <class T> [[gnu::section(".mysection")]] void template_func() { } } // namespace /* anonymous */ void (*ptr1)() = &regular_func; void (*ptr2)() = &template_func<int>; 

With clang, the characters for regular_func and template_func<int> are placed in .mysection , as I expected.

 $ clang++ -std=c++14 a.cpp -c && objdump -t ao | 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 does not fit in .mysection , but in the .text.* Section.

 $ g++ -std=c++14 a.cpp -c && objdump -t ao | 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 am using clang-3.7.1 and gcc-5.3.0.

How to force gcc to put the function created by the template in a separate section?

+5
source share
1 answer

This may be a little comfort, but GCC agrees if you apply the section attribute to an explicit instance of template <class T> void template_func() , for each T that you want to create, for example,

 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)() = &regular_func; void (*ptr2)() = &template_func<int>; 

Then:

 $ g++ -std=c++14 a.cpp -c && objdump -C -t ao | 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 

therefore, each compiler must have its own path through conditional compilation.

In addition, this fix brings an additional headache that you must somehow ensure that template_func() cannot be created for any T that you did not explicitly specify instantiated.

You can achieve this by statically asserting in the body of the function template that T is one of the types A,B,C... that you allow to create. Then, if it is always created using T = D , static_assert triggered; you can add D to the list and add an explicit instance 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)() = &regular_func; void (*ptr2)() = &template_func<int>; void (*ptr3)() = &template_func<float>; void (*ptr4)() = &template_func<char>; // <-- static_assert fails 
+2
source

Source: https://habr.com/ru/post/1245966/


All Articles