功能本地静态为Windows XP生成故障代码



我最初将其发布在返回工程的stackexchange上,不确切地知道它的属性。我决定无论如何都会在这里发布。

最近,Microsoft Visual Studio 2015编译器最终符合C 标准授权,以生成用于本地静态功能的线程安全代码。在大多数情况下,这很好,但是我遇到了Windows XP上的情况,以下3个说明导致炸毁:

mov     eax,dword ptr fs:[0000002Ch]
mov     ecx,dword ptr [MyModule!_tls_index (102eea44)]
mov     ecx,dword ptr [eax+ecx*4]

显然,编译器似乎通过首先戳入当前线程的TLS插槽来实现线程安全。fs:2Ch应该导致每个文档的TLS数组。但是,在Windows XP上,fs:2Ch似乎没有设置。这为我返回0,下一个指令(_tls_index也为0)也导致了第三指令在访问无效的内存时爆炸。

有人知道为什么可能在Windows XP上设置fs:2Ch吗?函数本地静态都在我们的代码上使用,我无法想象没有其他人遇到这个。

update

我已经仔细考虑了我对此问题应用的每个标签。请不要添加或删除任何东西。

在C 11标准中,具有静态或线程存储持续时间的块范围变量必须在任何其他初始化之前对零定位。当控制首次通过变量的声明时,就会发生初始化。如果在初始化期间抛出异常,则该变量被视为非初始化,并且初始化被重新定义,下次控制通过声明。如果控件同时输入声明,则在完成初始化时同时执行块。如果控制在初始化期间递归地重新输入声明,则行为是不确定的。默认情况下,Visual Studio从Visual Studio 2015开始实现此标准行为。可以通过设置/zc:threadSafeInit编译器选项明确指定此行为。 静态局部变量的线程安全初始化依赖于通用C运行时库(UCRT)中实现的代码。为了避免对UCRT依赖,或在Visual Studio 2015之前保留Visual Studio版本的非线程安全初始化行为,请使用/ZC:ThreadSafeNit-选项。如果您知道不需要线程安全,请使用此选项在静态本地声明周围生成稍小,更快的代码。线程安全的静态局部变量使用线程本地存储(TLS)在内部进行有效的执行,以提供有效的执行。此功能的实现取决于Windows操作系统支持Windows Vista和后来的操作系统中的功能。Windows XP,Windows Server 2003和较旧的操作系统没有此支持,因此它们没有获得效率优势。这些操作系统还对可以加载的TLS部分的数量有下限。超过TLS部分限制可能会导致崩溃。如果这是您的代码中的问题,尤其是必须在旧操作系统上运行的代码中,请使用/zc:threadSafeInit-禁用线程安全初始化代码。

彼得·费里(Peter Ferrie)在反向工程中得到了这个问题的回答。

https://reverseengineering.stackexchange.com/a/14186/15780

最新更新