首页
社区
课程
招聘
[原创]线程本地存储TLS(Thread Local Storage)的原理和实现——实现探究
发表于: 2012-7-3 16:18 5708

[原创]线程本地存储TLS(Thread Local Storage)的原理和实现——实现探究

2012-7-3 16:18
5708

本文为线程本地存储TLS系列之实现探究。
我们在上一篇线程本地存储TLS(Thread Local Storage)的原理和实现——分类和原理中曾经说过TLS可以分为两类:静态TLS和动态TLS。然后又分别说明了两者在程序实现时的用法,并且还说明了windows对这两类TLS的实现原理,我们本文的目的是从底层实现的角度深入探究,深刻理解原理。
先考虑以下两个问题:
1、在上一篇中,我们说到静态TLS数据是在编译时放入.tls节,然后在系统加载程序时,会去寻找.tls节,并且分配一个足够大的内存空间来存放所有这些静态TLS变量。那么问题是,当程序加载后,对静态TLS数据分配的内存空间在哪里呢?用什么来表示呢?
2、在上一篇中,我们说到动态TLS是存放在每一个线程独立的TLS slot数组中,这个数组的大小是TLS_MINIMUM_AVAILABLE维,那么这个数组在哪里呢?TlsSetValue和TlsGetValue应该就是访问的这个数组,在取得索引的情况下,如果我们知道这个数组的位置,那么我们是否完全就能抛开上面两个函数自己读写来测试呢?

一、线程环境块TEB
在给出具体程序之前,我们有必要先讨论一下线程环境块TEB。
我们知道,每个线程都有属于自己的一系列数据,这些数据就是通过TEB来管理,当然就包括像TLS这样的线程私有数据。那么TEB的结构是什么样的呢?在微软的文档和头文件上,我没有查到TEB完整的信息,不过我们还是可以通过Windbg得到的,以下是TEB的详细展开信息:

0:001> dt -b nt!_TEB
ntdll!_TEB
   +0x000 NtTib            : _NT_TIB
      +0x000 ExceptionList    : Ptr32 
      +0x004 StackBase        : Ptr32 
      +0x008 StackLimit       : Ptr32 
      +0x00c SubSystemTib     : Ptr32 
      +0x010 FiberData        : Ptr32 
      +0x010 Version          : Uint4B
      +0x014 ArbitraryUserPointer : Ptr32 
      +0x018 Self             : Ptr32 
   +0x01c EnvironmentPointer : Ptr32 
   +0x020 ClientId         : _CLIENT_ID
      +0x000 UniqueProcess    : Ptr32 
      +0x004 UniqueThread     : Ptr32 
   +0x028 ActiveRpcHandle  : Ptr32 
   +0x02c ThreadLocalStoragePointer : Ptr32 
   +0x030 ProcessEnvironmentBlock : Ptr32 
   +0x034 LastErrorValue   : Uint4B
   +0x038 CountOfOwnedCriticalSections : Uint4B
   +0x03c CsrClientThread  : Ptr32 
   +0x040 Win32ThreadInfo  : Ptr32 
   +0x044 User32Reserved   : Uint4B
   +0x0ac UserReserved     : Uint4B
   +0x0c0 WOW32Reserved    : Ptr32 
   +0x0c4 CurrentLocale    : Uint4B
   +0x0c8 FpSoftwareStatusRegister : Uint4B
   +0x0cc SystemReserved1  : Ptr32 
   +0x1a4 ExceptionCode    : Int4B
   +0x1a8 ActivationContextStack : _ACTIVATION_CONTEXT_STACK
      +0x000 Flags            : Uint4B
      +0x004 NextCookieSequenceNumber : Uint4B
      +0x008 ActiveFrame      : Ptr32 
      +0x00c FrameListCache   : _LIST_ENTRY
         +0x000 Flink            : Ptr32 
         +0x004 Blink            : Ptr32 
   +0x1bc SpareBytes1      : UChar
   +0x1d4 GdiTebBatch      : _GDI_TEB_BATCH
      +0x000 Offset           : Uint4B
      +0x004 HDC              : Uint4B
      +0x008 Buffer           : Uint4B
   +0x6b4 RealClientId     : _CLIENT_ID
      +0x000 UniqueProcess    : Ptr32 
      +0x004 UniqueThread     : Ptr32 
   +0x6bc GdiCachedProcessHandle : Ptr32 
   +0x6c0 GdiClientPID     : Uint4B
   +0x6c4 GdiClientTID     : Uint4B
   +0x6c8 GdiThreadLocalInfo : Ptr32 
   +0x6cc Win32ClientInfo  : Uint4B
   +0x7c4 glDispatchTable  : Ptr32 
   +0xb68 glReserved1      : Uint4B
   +0xbdc glReserved2      : Ptr32 
   +0xbe0 glSectionInfo    : Ptr32 
   +0xbe4 glSection        : Ptr32 
   +0xbe8 glTable          : Ptr32 
   +0xbec glCurrentRC      : Ptr32 
   +0xbf0 glContext        : Ptr32 
   +0xbf4 LastStatusValue  : Uint4B
   +0xbf8 StaticUnicodeString : _UNICODE_STRING
      +0x000 Length           : Uint2B
      +0x002 MaximumLength    : Uint2B
      +0x004 Buffer           : Ptr32 
   +0xc00 StaticUnicodeBuffer : Uint2B
   +0xe0c DeallocationStack : Ptr32 
   +0xe10 TlsSlots         : Ptr32 
   +0xf10 TlsLinks         : _LIST_ENTRY
      +0x000 Flink            : Ptr32 
      +0x004 Blink            : Ptr32 
   +0xf18 Vdm              : Ptr32 
   +0xf1c ReservedForNtRpc : Ptr32 
   +0xf20 DbgSsReserved    : Ptr32 
   +0xf28 HardErrorsAreDisabled : Uint4B
   +0xf2c Instrumentation  : Ptr32 
   +0xf6c WinSockData      : Ptr32 
   +0xf70 GdiBatchCount    : Uint4B
   +0xf74 InDbgPrint       : UChar
   +0xf75 FreeStackOnTermination : UChar
   +0xf76 HasFiberData     : UChar
   +0xf77 IdealProcessor   : UChar
   +0xf78 Spare3           : Uint4B
   +0xf7c ReservedForPerf  : Ptr32 
   +0xf80 ReservedForOle   : Ptr32 
   +0xf84 WaitingOnLoaderLock : Uint4B
   +0xf88 Wx86Thread       : _Wx86ThreadState
      +0x000 CallBx86Eip      : Ptr32 
      +0x004 DeallocationCpu  : Ptr32 
      +0x008 UseKnownWx86Dll  : UChar
      +0x009 OleStubInvoked   : Char
   +0xf94 TlsExpansionSlots : Ptr32 
   +0xf98 ImpersonationLocale : Uint4B
   +0xf9c IsImpersonating  : Uint4B
   +0xfa0 NlsCache         : Ptr32 
   +0xfa4 pShimData        : Ptr32 
   +0xfa8 HeapVirtualAffinity : Uint4B
   +0xfac CurrentTransactionHandle : Ptr32 
   +0xfb0 ActiveFrame      : Ptr32 
   +0xfb4 SafeThunkCall    : UChar
   +0xfb5 BooleanSpare     : UChar
//通过windgb查看_TEB得到的我的系统(winXP+SP3)中的_TEB的实现
struct STEB
{
    NT_TIB NtTib;
    PVOID EnvironmentPointer;
    //中间若干数据,与此处研究无关,故不展开,只标记偏移。下面的Reserved2,Reserved3也是同理
    BYTE Reserved1[12]; 
    PVOID ThreadLocalStoragePointer;    //指向存放静态TLS数据的地址的指针的地址
    BYTE Reserved2[3552];
    PVOID TlsSlots[64];                    //指向存放动态TLS数据的TLS Slot数组
    BYTE Reserved3[132];
    PVOID TlsExpansionSlots;             //当索引大于63时,TlsSlots数组存不下了,就会新分配内存来存放,并且将指针记录在这里
    //后面还有若干数据,与此处研究无关,故省略
};

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 6
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//