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.)
This commit is contained in:
Heschi Kreinick
2019-09-04 12:01:53 -04:00
committed by Derek Parker
parent dd3c2d63cc
commit 8954858ee8

View File

@ -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