【发布时间】:2011-03-04 01:14:07
【问题描述】:
操作系统:Windows XP 64 位,SP2。
我有一个不寻常的问题。我正在将一些代码从 32 位移植到 64 位。 32 位代码工作得很好。但是当我为 64 位版本调用 CreateThread() 时,调用失败。我有三个地方失败了。 2 调用 CreateThread()。 1 调用调用 CreateThread() 的 beginthreadex()。
所有三个调用都失败,错误代码为 0x3E6,“对内存位置的访问无效”。
问题是所有输入参数都正确。
HANDLE h;
DWORD threadID;
h = CreateThread(0, // default security
0, // default stack size
myThreadFunc, // valid function to call
myParam, // my param
0, // no flags, start thread immediately
&threadID);
对 CreateThread() 的所有三个调用都是由我在程序执行开始时注入目标程序的 DLL 进行的(这是在程序开始执行 main()/WinMain() 之前) .如果我通过一个菜单从目标程序(相同的参数)调用 CreateThread(),它就可以工作。相同的参数等。奇怪。
如果我传递 NULL 而不是 &threadID,它仍然会失败。
如果我将 NULL 作为 myParam 传递,它仍然会失败。
我没有从 DllMain() 内部调用 CreateThread,所以这不是问题。我很困惑,在 Google 等上搜索没有显示任何相关答案。
如果有人以前看过这个或有任何想法,请告诉我。
感谢阅读。
回答
简答:x64 上的堆栈帧需要 16 字节对齐。
更长的答案: 在将我的头撞到调试器墙上并发布对各种建议的响应(所有这些都在某种程度上有所帮助,促使我尝试新的方向)之后,我开始探索在调用 CreateThread() 之前堆栈上的内容的假设。这被证明是一个红鲱鱼,但它确实导致了解决方案。
向堆栈添加额外数据会更改堆栈帧对齐方式。迟早其中一项测试会让您达到 16 字节堆栈帧对齐。那时代码起作用了。所以我回顾了我的步骤,开始将 NULL 数据放入堆栈,而不是我认为的正确值(我一直在推送返回地址以伪造调用帧)。它仍然有效 - 所以数据并不重要,它必须是实际的堆栈地址。
我很快意识到堆栈是 16 字节对齐的。以前我只知道数据的 8 字节对齐。这个microsoft document explains all the alignment requirements。
如果堆栈帧在 x64 上不是 16 字节对齐,则编译器在将数据推送到堆栈时可能会将大(8 字节或更多)数据放在错误的对齐边界上。
因此我遇到了问题 - 使用未在 16 字节边界上对齐的堆栈调用挂钩代码。
对齐要求的快速摘要,表示为大小:对齐
- 1:1
- 2:2
- 4 : 4
- 8:8
- 10:16
- 16 : 16
任何大于 8 字节的内容都在下一个 2 的幂边界上对齐。
我认为微软的错误代码有点误导。初始的 STATUS_DATATYPE_MISALIGNMENT 可以表示为 STATUS_STACK_MISALIGNMENT,这样会更有帮助。但是随后将 STATUS_DATATYPE_MISALIGNMENT 变成 ERROR_NOACCESS - 这实际上掩盖和误导了问题所在。非常无益。
感谢所有发布建议的人。即使我不同意这些建议,它们也会促使我在各种各样的方向上进行测试(包括我不同意的方向)。
这里写了更详细的数据类型错位问题描述:64 bit porting gotcha #1! x64 Datatype misalignment.
【问题讨论】:
-
myParam到底是什么(即它的声明和初始化)? -
myParam 在所有情况下都是指向某个内存的指针(通常是“this”)。指针在传递时始终是有价值的。为什么这很重要?它不会访问它的内容,它只是一个要传递给线程函数的值。
-
@Michael,我尝试将 NULL 作为 myParam 传递。仍然失败。
-
你能看到错误信息是什么吗?您可以为此目的使用此功能pastebin.com/h72GM9fJ
-
@Luke,值:相同。绝对地。我现在已经扩展了检查。即使我传入一个在 16 字节边界上对齐的过程、一个 16 字节对齐的参数和一个指向 16 字节边界上的 DWORD 的 DWORD 指针,我仍然会失败。我认为 8 字节对齐就足够了,但发现对某些需要 16 字节对齐的结构(例如:CONTEXT)的引用,所以我这样做太过分了。没有快乐,仍然失败。
标签: windows 64-bit multithreading alignment 32bit-64bit