2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #ifndef incl_HPHP_VM_CODE_GEN_TLS_X64_H_
18 #define incl_HPHP_VM_CODE_GEN_TLS_X64_H_
20 #include "hphp/runtime/vm/jit/vasm-gen.h"
21 #include "hphp/runtime/vm/jit/vasm-instr.h"
22 #include "hphp/runtime/vm/jit/vasm-reg.h"
24 #include "hphp/util/asm-x64.h"
25 #include "hphp/util/thread-local.h"
27 namespace HPHP
{ namespace jit
{ namespace x64
{ namespace detail
{
29 ///////////////////////////////////////////////////////////////////////////////
32 * We support x64 linux (linked off FS), and x64 MacOS using some reverse
33 * engineering of their generated code.
38 * x86 terminology review: "Virtual addresses" are subject to both segmented
39 * translation and paged translation. "Linear addresses" are post-segmentation
40 * address, subject only to paging. C and C++ generally only have access to
41 * bitwise linear addresses.
43 * On Linux, TLS data live at negative virtual addresses off FS: the first
44 * datum is typically at VA(FS:-sizeof(datum)). Linux's x64 ABI stores the
45 * linear address of the base of TLS at VA(FS:0). While this is just a
46 * convention, it is firm: gcc builds binaries that assume it when, e.g.,
47 * evaluating "&myTlsDatum".
49 * The virtual addresses of TLS data are not exposed to C/C++. To figure it
50 * out, we take a datum's linear address, and subtract it from the linear
51 * address where TLS starts.
54 Vptr
emitTLSAddr(Vout
& /*v*/, TLSDatum
<T
> datum
) {
55 uintptr_t vaddr
= uintptr_t(datum
.tls
) - tlsBase();
56 return Vptr
{baseless(vaddr
), Segment::FS
};
60 Vreg
emitTLSLea(Vout
& v
, TLSDatum
<T
> datum
) {
61 auto const vaddr
= v
.cns(uintptr_t(datum
.tls
) - tlsBase());
62 auto const addr
= v
.makeReg();
63 v
<< addqmr
{Vptr
{baseless(0), Segment::FS
}, vaddr
, addr
, v
.makeReg()};
69 * In MacOS an __thread variable has a "key" allocated in global memory, under
70 * the name of the object. The key consists of three longs. The first holds
71 * the address of a function, which if called with $rdi pointing at the key
72 * (i.e., $rdi = &key; call 0x0($rdi)) will return the address of the thread
73 * local (possibly allocating it, if this is the first time its been accessed
74 * in the current thread).
76 * The function is very short (in the case that the thread local has already
77 * been allocated), and preserves all the registers except for $rax (which gets
78 * the address of the thread local)---so we could just use it to access the
79 * thread locals. But we can do better.
81 * The second long contains a gs-relative index to a pointer to the block of
82 * memory containing the thread-local, and the third long contains the offset
83 * to it within that block. So if $rdi points at the key,
86 * movq gs:(,$rax,8), $rax
89 * will get us the address of the thread local.
91 * But we can still do better. key[1] and key[2] are constants for the
92 * duration of the program; so we can burn their values into the tc:
94 * movq gs:{key[1]*8}, $rax
97 * But note that the add will often fold into a following load or store.
99 * So the only remaining problem is to get the address of the key:
101 * __asm__("lea %1, %0" : "=r"(ret) : "m"(tlvar));
103 * Unfortunately, clang is too smart here, and converts the lea into:
109 * Fortunately, the helper preserves all regs (except $rax), and so $rdi now
110 * has the address of the key. We use that trick in the OSX version of
113 * Finally note that all of this is only valid if the thread local has already
114 * been accessed in the current thread---but we can easily ensure that (it's
115 * already true for any ThreadLocalNoCheck variable).
118 Vptr
emitTLSAddr(Vout
& v
, TLSDatum
<T
> datum
) {
119 auto const scratch
= v
.makeReg();
121 v
<< load
{Vptr
{baseless(datum
.raw
[1] * 8), Segment::GS
}, scratch
};
122 return scratch
[datum
.raw
[2]];
126 Vreg
emitTLSLea(Vout
& v
, TLSDatum
<T
> datum
) {
127 auto const b
= v
.makeReg();
128 v
<< lea
{detail::emitTLSAddr(v
, datum
), b
};
134 ///////////////////////////////////////////////////////////////////////////////