如何在 linux amd64 上找到当前线程的 TLS 段?

How to find TLS segments of the current thread on linux amd64?

我正在寻找一种方法来找出 linux、amd64 上当前线程的 TLS 段的内存地址。适用于 OSX.

的解决方案的奖励积分

研究了各种语言运行时或 GC(如 boehm),但到目前为止无法通过多层抽象来支持所有类型的系统。任何帮助表示赞赏。

在 Linux 上,线程特定段是通过 arch_prtcl(ARCH_SET_FS, <addr>) 调用设置的。您可以通过 arch_prctl(ARCH_GET_FS, ...).

查看当前线程中设置的内容

Bonus point for a solution that works on OSX.

OSX 是一个完全不同的 OS,并且使用完全不同的机制来支持 TLS。

你看过我和 Martin 在 druntime 中提出的解决方案了吗?

我们在那里所做的归结为扫描类型为 PT_TLS 的段的相应 dl_phdr_info 中的段(通过使用 dl_iterate_phdr 查找正确的段获得),以及存储其模块 ID 和大小。

然后,您可以通过调用 __tls_get_addr 偏移量 0 和模块 ID(某些拱门上有偏移量)来获取当前线程地址范围的开始,并通过简单地添加结束你确定的尺寸。如果你不需要支持共享库,你也可以简单地在 x86 上使用 fs/gs(如果你想 link 静态可执行文件可能需要)。


这适用于 Linux 和 FreeBSD(可能还有其他 ELF 平台),但不适用于 OS X。到目前为止,我能想到的最好的是:

void _d_dyld_getTLSRange(void* arbitraryTLSSymbol, void** start, size_t* size) {
    dyld_enumerate_tlv_storage(
        ^(enum dyld_tlv_states state, const dyld_tlv_info *info) {
            assert(state == dyld_tlv_state_allocated);
            if (info->tlv_addr <= arbitraryTLSSymbol &&
                arbitraryTLSSymbol < (info->tlv_addr + info->tlv_size)
            ) {
                // Found the range we are looking for.
                *start = info->tlv_addr;
                *size = info->tlv_size;
            }
        }
    );
}
</pre>

目前在 LDC 的 druntime 中使用的原始实现并不能很好地处理共享库,而且 dyld_enumerate_tlv_storage 来自 dyld_priv.h,这可能会也可能不会成为 App Store 发布的问题。