Page MenuHomeFreeBSD

rtld: Fix i386/amd64 TP offset when p_vaddr % p_align != 0
ClosedPublic

Authored by fbsd-phab_maskray.me on Aug 14 2021, 3:55 AM.
Tags
None
Referenced Files
Unknown Object (File)
Fri, May 3, 12:04 AM
Unknown Object (File)
Thu, Apr 25, 8:25 PM
Unknown Object (File)
Wed, Apr 24, 6:54 AM
Unknown Object (File)
Fri, Apr 19, 7:56 PM
Unknown Object (File)
Fri, Apr 19, 7:56 PM
Unknown Object (File)
Wed, Apr 17, 10:21 AM
Unknown Object (File)
Wed, Apr 17, 10:00 AM
Unknown Object (File)
Sat, Apr 6, 3:18 PM
Subscribers

Details

Summary

For a Variant II architecture, the TP offset of a TLS symbol is st_value -
tlsoffset + r_addend. tlsoffset is computed by either calculate_tls_offset
or calculate_first_tls_offset.

The return value of calculate_first_tls_offset is the smallest integer satisfying
res >= size and (-res)%p_align = p_vaddr%p_align (= p_offset%p_align).
(The formula is a bit contrived. The basic idea is to subtract the minimum
integer from size+align-1 so that the result has the expected remainder.)

Tested on amd64 by linking x.o and y.o with a patched LLD
(https://reviews.freebsd.org/D24366#641771) so that p_vaddr%p_align!=0.
calculate_first_tls_offset must match @TPOFF computed by the linker.

// x.s
.globl foo; foo: movl %fs:a@TPOFF, %eax; ret
.section .tdata,"awT"; a: .long 42
.section .tbss,"awT",@nobits; .balign 512

// y.c
#include <stdio.h>
int foo();
int main() { printf("%d\n", foo()); }

# Before the patch: 0 (incorrect)
# With the patch: 42

(
I use clang -Wl,--reproduce=rep.tar to create a tarball, then
replace libc.so.7 with the freshly built amd64.amd64/lib/libc/libc.so.7
and point --dynamic-linker to the freshly built amd64.amd64/libexec/rtld-elf/ld-elf.so.1
)

You may use: git commit --amend --author='Fangrui Song <i@maskray.me>'

Diff Detail

Repository
rS FreeBSD src repository - subversion
Lint
Lint Passed
Unit
No Test Coverage
Build Status
Buildable 41038
Build 37927: arc lint + arc unit