From 8954858ee803c8ddea6fa03f821d785e21b809d0 Mon Sep 17 00:00:00 2001 From: Heschi Kreinick Date: Wed, 4 Sep 2019 12:01:53 -0400 Subject: [PATCH] proc: round TLS segment size to its alignment (#1682) The fix for #1428 was buggy, partly because I communicated poorly. Sorry about that. The size of the TLS segment should be padded such that TLS addresses are congruent in the file to where they will end up memory, i.e. (tlsoffset%align) == (vaddr%align). In most cases, vaddr will be aligned and it won't matter, but if not then simply aligning the end of the segment is incorrect. This should be right. (For the record, the current rounding logic is working in bits, but PtrSize is in bytes, so it wasn't working as originally intended either.) --- pkg/proc/bininfo.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pkg/proc/bininfo.go b/pkg/proc/bininfo.go index 270473af..781e1a31 100644 --- a/pkg/proc/bininfo.go +++ b/pkg/proc/bininfo.go @@ -980,9 +980,13 @@ func (bi *BinaryInfo) setGStructOffsetElf(image *Image, exe *elf.File, wg *sync. bi.gStructOffset = ^uint64(8) + 1 // -8 return } - memsz := tls.Memsz - memsz = (memsz + uint64(bi.Arch.PtrSize()) - 1) & ^uint64(bi.Arch.PtrSize()-1) // align to pointer-sized-boundary + // According to https://reviews.llvm.org/D61824, linkers must pad the actual + // size of the TLS segment to ensure that (tlsoffset%align) == (vaddr%align). + // This formula, copied from the lld code, matches that. + // https://github.com/llvm-mirror/lld/blob/9aef969544981d76bea8e4d1961d3a6980980ef9/ELF/InputSection.cpp#L643 + memsz := tls.Memsz + (-tls.Vaddr-tls.Memsz)&(tls.Align-1) + // The TLS register points to the end of the TLS block, which is // tls.Memsz long. runtime.tlsg is an offset from the beginning of that block. bi.gStructOffset = ^(memsz) + 1 + tlsg.Value // -tls.Memsz + tlsg.Value