net/frr[89] revealed an interesting edge-case on arm when dynamically linking
a shared library that declares more than one static TLS variable with at least one
using the "initial-exec" TLS model. In the case of frr[89], this library was libfrr.so
which essentially does the following:
#include <stdio.h>
#include "lib.h"
static __thread int *a
__attribute__((tls_model("initial-exec")));
void lib_test()
{
static __thread int b = -1;
printf("&a = %p\n", &a);
printf(" a = %p\n", a);
printf("\n");
printf("&b = %p\n", &b);
printf(" b = %d\n", b);
}Allocates a file scoped static __thread pointer with tls_model("initial-exec") and
later a block scoped TLS int. Notice in the above minimal reproducer, b == -1.
The relocation process does the wrong thing and ends up pointing both a and b
at the same place in memory.
The output of the above in the broken state is:
&a = 0x4009c018 a = 0xffffffff &b = 0x4009c018 b = -1
With the patch applied, the output becomes:
&a = 0x4009c01c a = 0x0 &b = 0x4009c018 b = -1
Sponsored by: Rubicon Communications, LLC ("Netgate")