Search code examples
linuxgccx86-64thread-local-storage

GCC Common Variable Attribute on TLS model


Referring to GCC website. It is stated that

The tls_model attribute sets thread-local storage model (see Thread-Local) of a particular __thread variable, overriding -ftls-model= command-line switch on a per-variable basis. The tls_model argument should be one of global-dynamic, local-dynamic, initial-exec or local-exec. Not all targets support this attribute.

In order to look into the differences of the assembly generated for different TLS models, a class was created with three __thread variables.

#include <cstdint>

class Holder
{
public:
    static int32_t calc();
    static int32_t calc2();
    static int32_t calc3();
    static __thread int32_t value  __attribute__ ((tls_model("initial-exec")));
    static __thread int32_t value2  __attribute__ ((tls_model("local-dynamic")));
    static __thread int32_t value3;
};

__thread int32_t Holder::value;
__thread int32_t Holder::value2;
__thread int32_t Holder::value3;

int32_t Holder::calc()
{
    return value * 2;
}

int32_t Holder::calc2()
{
    return value2 * 2;
}

int32_t Holder::calc3()
{
    return value3 * 2;
}

This is compiled with -c -shared -fPIC -O3 flags. However, it is noted that the attribute does not yield any difference in corresponding calc functions. (All using the __tls_get_addr in the corresponding calc function.) However, if -ftls-model=initial-exec flag is added, it does indeed change the TLS model but all being overridden to use inital-exec (all calc functions using @gottpoff(%rip))

Using the online compiler explorer, it is found that both clang (LLVM) and icc seem to honour the attribute but not gcc. It also seems to contradict with the description in GCC website (overriding on a per-variable basis). One may try it on this and switch to different compliers.

Is there a reason that GCC removed the ability to override the per variable setting? Or did I do something wrong or have the wrong expectation?

Thanks for any help and explanation in advance.


Solution

  • This is a bug, possibly in the C++ frontend, and/or in attribute merging code. If you move or duplicate the attribute from the declaration on the definition, it works as intended. If you eliminate the definitions, and leave only the declarations, it also works according to the documentation. Basically, each definition does not appear to properly inherit the attribute from the preceding declaration. This is worthy of a bugreport at https://gnu.gnu.org/bugzilla