Changeset View
Standalone View
head/libexec/rtld-elf/amd64/reloc.c
Show First 20 Lines • Show All 546 Lines • ▼ Show 20 Lines | |||||
void *__tls_get_addr(tls_index *ti) | void *__tls_get_addr(tls_index *ti) | ||||
{ | { | ||||
Elf_Addr** segbase; | Elf_Addr** segbase; | ||||
__asm __volatile("movq %%fs:0, %0" : "=r" (segbase)); | __asm __volatile("movq %%fs:0, %0" : "=r" (segbase)); | ||||
return tls_get_addr_common(&segbase[1], ti->ti_module, ti->ti_offset); | return tls_get_addr_common(&segbase[1], ti->ti_module, ti->ti_offset); | ||||
} | } | ||||
size_t | |||||
calculate_first_tls_offset(size_t size, size_t align, size_t offset) | |||||
{ | |||||
size_t res; | |||||
res = roundup(size, align); | |||||
fbsd-phab_maskray.me: Considering a PT_TLS segment with p_vaddr == 4, p_align == 8 and p_memsz == 9, the computed… | |||||
kibAuthorUnsubmitted Done Inline ActionsNobody ever answered by query about the right formula. Please provide the algorithm that should be implemented by rtld. kib: Nobody ever answered by query about the right formula. Please provide the algorithm that… | |||||
fbsd-phab_maskray.meUnsubmitted Not Done Inline Actionshttps://github.com/llvm/llvm-project/blob/main/lld/ELF/InputSection.cpp#L665 is the right formula. fbsd-phab_maskray.me: https://github.com/llvm/llvm-project/blob/main/lld/ELF/InputSection.cpp#L665 is the right… | |||||
kibAuthorUnsubmitted Done Inline Actions20 mod 8 == 12 mod 8 == 4. Can you provide self-contained elf binary that demonstrates the problem you complain about? It might be that the problem is not in the calculation, but in the alignment of the end of the tls segment (from which this offset is subtracted). kib: 20 mod 8 == 12 mod 8 == 4. Can you provide self-contained elf binary that demonstrates the… | |||||
fbsd-phab_maskray.meUnsubmitted Not Done Inline Actions
This is not sufficient. For the local-exec TLS model, the linker and the dynamic loader must agree on the TP offset, otherwise if you take the address from an executable (local-exec) and take the address from a DF_STATIC_TLS shared object (initial-exec movq tls@GOTTPOFF(%rip), %rax), the two addresses may mismatch.
LLD has a workaround to force p_vaddr%p_align = 0. You can delete the else if (Out::tlsPhdr && Out::tlsPhdr->firstSec == p->firstSec) branch in https://reviews.llvm.org/D64906 , then LLD can make p_vaddr%p_align != 0 if sh_addralign(.tdata) < sh_addralign(.tbss), e.g. # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o # RUN: ld.lld %t.o -o %t # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s # -alignTo(p_memsz, p_align) = -alignTo(4, 64) = -64 # CHECK: movl %fs:-64, %eax movl %fs:a@TPOFF, %eax .section .tdata,"awT" a: .long 0 .section .tbss,"awT",@nobits .balign 64 I don't spend time to craft an example to make the FreeBSD rtld inconsistent, but with appropriate sh_size(.tdata) you can. I wrote most stuff in https://maskray.me/blog/2021-02-14-all-about-thread-local-storage fbsd-phab_maskray.me: > 20 mod 8 == 12 mod 8 == 4.
This is not sufficient. For the local-exec TLS model, the linker… | |||||
offset &= align - 1; | |||||
if (offset != 0) | |||||
res += align - offset; | |||||
return (res); | |||||
} | |||||
size_t | |||||
calculate_tls_offset(size_t prev_offset, size_t prev_size __unused, size_t size, | |||||
size_t align, size_t offset) | |||||
{ | |||||
size_t res; | |||||
res = roundup(prev_offset + size, align); | |||||
offset &= align - 1; | |||||
if (offset != 0) | |||||
res += align - offset; | |||||
return (res); | |||||
} | |||||
size_t | |||||
calculate_tls_end(size_t off, size_t size __unused) | |||||
{ | |||||
return (off); | |||||
} |
Considering a PT_TLS segment with p_vaddr == 4, p_align == 8 and p_memsz == 9, the computed offset is 20 (does that mean TP-20?)
LLD computed offset is -12 (matches musl libc)
https://github.com/llvm/llvm-project/blob/main/lld/ELF/InputSection.cpp#L665 The offset equals p_vaddr modulo p_align.
Local-exec TLS offsets are a protocol between the linker and the dynamic loader. Their values must match.