thread_local是怎么实现的(简要介绍)

如果只分析过Debug模式编译的PE文件,一般会认为thread_local静态数据是通过.tls节实现的,但其实Release模式一般不使用.tls节,而是使用另一种更强大的方式,这种方式还支持构造函数和析构函数。

在DLL中,DllMain函数在线程建立和撤销时会被Windows调用,通过第二个参数可以区分调用原因。

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH: // 主线程创建
    case DLL_THREAD_ATTACH: // 其它线程创建
    case DLL_THREAD_DETACH: // 其它线程退出
    case DLL_PROCESS_DETACH: // 主线程退出
        break;
    }
    return TRUE;
}

thread_local主线程创建时运行构造函数时通过mainCRTStartup入口函数实现的,其它线程创建时运行构造函数,其它线程退出、主线程退出时运行析构函数是通过PE文件的IMAGE_TLS_DIRECTORY注册回调实现的,回调原型和DllMain函数完全一样。主线程建立时不使用回调函数是因为Windows此时调用回调的时机太早,程序依赖的DLL还没载入,什么都干不了。

Windows的PE加载器处理IMAGE_TLS_DIRECTORY时,相当于自动帮助程序进行了下面的操作:调用TlsAlloc分配TLS指针槽(程序启动时)、分配内存区域并用模板数据初始化然后调用TlsSetValue将分配的内存区域指针存入TLS指针槽(线程创建时)、在线程创建和退出时调用回调函数、释放内存区域(线程退出时)。

typedef VOID
(NTAPI *PIMAGE_TLS_CALLBACK) (
    PVOID DllHandle,
    DWORD Reason,
    PVOID Reserved
    );

typedef struct _IMAGE_TLS_DIRECTORY64 {
    ULONGLONG StartAddressOfRawData;
    ULONGLONG EndAddressOfRawData;
    ULONGLONG AddressOfIndex;         // PDWORD
    ULONGLONG AddressOfCallBacks;     // PIMAGE_TLS_CALLBACK *;
    DWORD SizeOfZeroFill;
    union {
        DWORD Characteristics;
        struct {
            DWORD Reserved0 : 20;
            DWORD Alignment : 4;
            DWORD Reserved1 : 8;
        } DUMMYSTRUCTNAME;
    } DUMMYUNIONNAME;

} IMAGE_TLS_DIRECTORY64;

typedef IMAGE_TLS_DIRECTORY64 * PIMAGE_TLS_DIRECTORY64;

typedef struct _IMAGE_TLS_DIRECTORY32 {
    DWORD   StartAddressOfRawData;
    DWORD   EndAddressOfRawData;
    DWORD   AddressOfIndex;             // PDWORD
    DWORD   AddressOfCallBacks;         // PIMAGE_TLS_CALLBACK *
    DWORD   SizeOfZeroFill;
    union {
        DWORD Characteristics;
        struct {
            DWORD Reserved0 : 20;
            DWORD Alignment : 4;
            DWORD Reserved1 : 8;
        } DUMMYSTRUCTNAME;
    } DUMMYUNIONNAME;

} IMAGE_TLS_DIRECTORY32;
typedef IMAGE_TLS_DIRECTORY32 * PIMAGE_TLS_DIRECTORY32;

 

发布了30 篇原创文章 · 获赞 1 · 访问量 5567
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览