rtld/arm: fix initial-exec (IE) thread-local storage relocation
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 Reviewed by: kib Sponsored by: Rubicon Communications, LLC ("Netgate") Differential Revision: https://reviews.freebsd.org/D42415/
This commit is contained in:
parent
6c3ae01cc7
commit
98fd69f009
|
@ -280,10 +280,13 @@ reloc_nonplt_object(Obj_Entry *obj, const Elf_Rel *rel, SymCache *cache,
|
|||
return -1;
|
||||
|
||||
tmp = (Elf_Addr)def->st_value + defobj->tlsoffset;
|
||||
if (__predict_true(RELOC_ALIGNED_P(where)))
|
||||
if (__predict_true(RELOC_ALIGNED_P(where))) {
|
||||
tmp += *where;
|
||||
*where = tmp;
|
||||
else
|
||||
} else {
|
||||
tmp += load_ptr(where);
|
||||
store_ptr(where, tmp);
|
||||
}
|
||||
dbg("TLS_TPOFF32 %s in %s --> %p",
|
||||
obj->strtab + obj->symtab[symnum].st_name,
|
||||
obj->path, (void *)tmp);
|
||||
|
|
Loading…
Reference in New Issue