如何调试平面 thunk

文章翻译 文章翻译
文章编号: 133722 - 查看本文应用于的产品
展开全部 | 关闭全部

本文内容

概要

调试平面的 thunk thunk 编译器生成会非常困难,因为 thunk 机制很复杂,能够跟踪 thunk 的调试工具难于使用。本文提供了一个总体战略的调试平面 thunk、 几个特定调试技术和解释如何解决许多常见的 thunking 问题一个故障排除指南。

更多信息

什么是目标 DLL 可以执行的限制

在开始调试 thunk 之前,请记住,有一些限制哪些目标 DLL 可以执行一个 thunk 内。这是因为一个基于 Win16 的应用程序,调用基于 Win32 的 DLL 不是一个基于 Win32 的过程 ; 同样,一个基于 Win32 的应用程序,调用基于 Win16 的 DLL 不是一个基于 Win16 的过程。常见的特定限制包括:

  • 您不能从基于 Win16 的应用程序,向基于 Win32 的 DLL 创建一个 thunk 内的线程。
  • 在基于 Win32 的 dll 调用的 thunk 代码应需要很少的堆栈空间,因为调用基于 Win16 的进程有更小的牌叠比基于 Win32 的应用程序。
  • 处理中断时,不为基于 Win32 的 dll 包含中断服务例程 (isr) 的基于 Win16 的 dll 必须 thunk。
  • 基于 Win32 的应用程序必须不将指针传递到堆栈上位于作为 thunk 或 $ 切换堆栈的基于 Win16 的 dll 调用的参数的数据。

为什么调试平面 thunk 可以会困难

调试平面 thunk 是很困难的因为平面 thunk 机制是一个复杂的一部分,Windows 内核的部分。从这一事实,它必须转换到 32-位已编译代码中的函数调用其复杂性花茎调用兼容的与 16 位代码,反之亦然。因为 32-位代码使用不同的数据类型,并且 CPU 注册从 16 位代码集平面 thunk 机制必须转换函数参数,切换堆栈,并转换返回值。它可实现速度,优化,但必须允许调用非抢先 Win16 代码抢先 Win32 代码。thunk 编译器使创建平面 thunk 比手动创建它们,更容易,但它不能杜绝出错。

调试平面 thunk 不困难,只因为本身机制复杂,但也是由于所需的调试工具更难母版。应用程序级别调试器,如 Microsoft Visual c + + 调试器和 WinDBG 不能跟踪通过 thunk 因为它们包含 32 位和 16 位代码,并会导致系统声称或释放该 Win16Mutex。若要跟踪通过一个 thunk,您需要使用如 WDEB386.EXE 系统级调试器。若要使用 WDEB386.EXE 主要的缺点是您需要知道知道英特尔 x86 微处理器的工作方式的英特尔 x86 程序集语言并记住许多调试器命令。

使用最佳的策略

对于调试 thunk 最佳策略是将相除,并应对,因为这样相对比较简单,并消除了大部分问题之前您需要通过在系统级调试器中的程序集语言代码的跟踪。平面 thunk 由基于 Win32 的 DLL 和一个基于 Win16 的 DLL 组成,因此有可能要测试每个在一起测试它们之前的隔离。 创建基于 Win16 的应用程序来测试基于 Win16 的 DLL,并创建一个基于 Win32 的应用程序来测试基于 Win32 的 DLL。这样,您可以使用各种调试工具来验证每一侧工作正常。

初步的检查表-前使用 Thunk 编译器编译

一旦验证每一侧工作正常了,则是将这两个一起,以测试本身 thunk 的时间。编译用 thunk 编译器 thunk 之前,进行初步检查以下各项:
  1. 在您的 thunk 脚本请确保每个函数具有正确的号码和类型的参数。还要确保参数类型由 thunk 编译器支持。如果它们不的是必须将参数传递是受支持的类型与数据以某种方式更改。
  2. 如果您将作为参数传递任何结构,请确保您使用相同的结构基于 Win32 的 DLL、 基于 Win16 的 DLL 和 thunk 脚本中包装。在您的 C/c + + 编译器的命令行和 thunk 编译器命令行中,您可以设置结构装箱。请注意 thunk 编译器的装箱开关是 16 位侧的小写和大写字母为 32 位侧。
  3. 请确保您正在以 thunking 的功能正确导出,并且使用调用约定,如果它们是 16 位或 $ _stdcall,如果它们是 32-位在 PASCAL。thunk 编译器不支持 _cdecl 和 __fastcall 调用约定。
  4. 请确保基于 Win32 的 DLL 调用 ThunkConnect32() 每次调用时其 DllMain() 函数。同样,请确保基于 Win16 的 DLL 导出的 DllEntryPoint() 函数,独立于其 LibMain() 调用 ThunkConnect16() 并返回 TRUE 如果 ThunkConnect16() 成功的。

    : 您实际调用 XXX_ThunkConnect16() 和 XXX_ThunkConnect32() 其中 XXX 是符号,定义具有 thunk 编译器的-t 开关。生成的 thunk 编译器代码使用这些符号来生成调用 ThunkConnect16() 和 ThunkConnect32 的表。
  5. 请确保在 thunk 编译器的命令行-t 开关中指定的值是相同的 Win32 和 Win16 thunk dll。该值还必须对应于 ThunkConnect 调用基于 Win16 的和基于 Win32 的 dll 中 (请参阅第 4 步中的注释) 的前缀。
  6. 验证基于 Win16 的 DLL 有 DLLEntryPoint 用 RESIDENTNAME 关键字在其模块定义 (.DEF) 文件中导出。不带 RESIDENTNAME 关键字 ThunkConnect32/ThunkConnect16 调用将失败并不会加载 dll。
  7. 验证 16 位 DLL 具有 XXX_ThunkData16 用 RESIDENTNAME 关键字在其模块定义 (.DEF) 文件中导出。
  8. 在基于 Win16 的 DLL 的生成文件中验证资源编译器会将该 DLL 标记为 4.0。如果它被标记为低于 4.0,它不会加载,并在 thunk 将失败。
  9. 如果您的 32 位到 16 位 thunk 函数返回的指针,请确保基类型是相同的大小在 thunk 的 16 位和 32 位面。不同基类型的大小是否 thunk 编译器发出错误消息,指出,"无法返回指针为非完全相同的类型"。要变通解决此问题的一种方法是以一个不同,但兼容,数据类型返回的指针。例如对于一个 thunk 不能返回的指针为 int,因为 int 是在 16 位端但 32-位一侧的四个字节的两个字节。更改从一个指针 thunk 的返回类型为 int 是指向 thunk 脚本和基于 Win16 的和基于 Win32 的 dll 的源代码中的长时间的。

    如果您编写 16 位到 32-位 thunk,返回的指针、 thunk 编译器会发出一条错误消息,声明、"指针类型可能不会返回。thunk 编译器不允许返回指针类型,因为一旦从 32 位函数返回在 thunk,指针不将指向正确的基于 Win32 的进程地址空间中的数据的 16 位到 32-位 thunk。这是因为所有基于 Win32 的进程的地址空间使用相同的范围地址,并且 preemptively 上下文切换。
  10. 如果链接器将报告"未解析外部"错误,并且该符号是对整个源的所有代码、 模块的定义文件和 thunk 脚本一致地拼写函数名称确保其原型的所有匹配项都保持一致。在 Win32 端 thunk 函数必须使用 __stdcall 类型来声明 ; Win16 侧必须用 PASCAL 类型声明该函数。在 c + + 项目中一定要声明和定义具有除了在 __stdcall 或 PASCAL 类型在 extern"C"链接说明符的 thunk 函数的两面。

trouble-Shooting 指南-后使用 Thunk 编译器编译

检查该 preliminaries 后,生成您 thunk dll,并尝试运行它们。如果运行它们继续进行进一步的测试,以确保它们是摇晃稳定。如果不运行使用下列故障排除指南确定并修复问题的原因。

在 Win32 侧 Win16 或 ThunkConnect32() ThunkConnect16() 失败:

  1. 运行系统 dll 的调试版本。KERNEL32.DLL 和 KRNL386.EXE 的调试版本包含很多的诊断消息,告诉您该 thunk 未初始化。若要进行系统 dll 的调试版本使用在 Win32 SDK 工具下的开始菜单中的"切换到调试 dll"图标。使用的"切换到无调试 dll"若要切换回零售版本。
  2. 验证基于 Win16 的 DLL 具有 ThunkConnect16() 的调用,并且基于 Win32 的 DLL 具有 ThunkConnect32() 相应的调用。如果其中一个缺少,然后其他将会失败,并将无法加载 thunk dll。
  3. 将断点放在您的 Win32 DLL DllMain(),若要查看哪些 dll 函数未加载 Win16 DLL 的 DllEntryPoint() 和 LibMain() 中。
如果 ThunkConnect16() 和 ThunkConnect32() 调用工作正常,但在 thunk 仍然不是以简化您 thunk 的时间。实际可以攻击这两种方式。第一次,启动从该 thunk 逐个删除参数,并重新编译它。或者,第二个,创建一个简单的 thunk 工作,并生成它,直到它无法通过执行以下步骤:
  1. 创建一个简单的 thunk,并执行它只是为了确保您具有正确设置了 thunk 机制。适合用于简单 thunk 是带有没有返回值和参数的函数。如果不能正常工作甚至简单的 thunk,运行通过初步的检查表上面以确保您具有正确设置的内容。然后转到步骤 2。
  2. 请检查以确保目标 DLL 和可找到并加载它依赖于任何 dll。如果缺少一个,或者加载程序找不到它在 thunk 将不起作用。
  3. 请确保您的目标 DLL 不执行某项,它不能在一个 thunk 的上下文中。
您有工作,一个简化的 thunk,但您实际 thunk 仍然不能正常工作后请按照下列步骤操作:
  1. 若要将参数添加到了一个简单 thunk 以确定参数是否会导致失败的一次。如果条件一个确保该参数是正确类型声明和定义具有相同数目和类型参数在两个 dll 和 thunk 编译器中的函数和该函数被声明为 PASCAL 或 _stdcall。
  2. 如果您的目标 DLL 是基于 Win16 的 DLL,并且它不能访问其全局或静态数据请确保已正确导出函数。如果您使用/GD 开关使用 Visual c + +,必须声明和定义该函数使用 __export 关键字基于 Win16 的 DLL 的源代码中。仅列出 DLL 的模块定义 (.DEF) 文件中的函数的名称不足够,因为编译器不处理.def 文件,因此它不会生成序言码和 epilog 代码导出函数的需要。
  3. 如果调用 LocalAlloc() 中您目标基于 Win16 的 DLL 原因一般保护 (GP) 错误,请确保您的函数导出第 2 步中所述。
  4. 如果您获得 GP 故障中 KERNEL32 只是基于 Win16 的函数返回您目标后,请确保在声明和定义为 PASCAL 目标函数。不能使用 C 调用约定。尽管在 C 或 c + + 代码但更有可能在程序集语言不常见,但请确保目标函数没有修改 DS、 SS、 BP、 SI,或 DI 寄存器。
  5. 如果您在基于 Win32 的目标函数返回后立即在 32 位形式转换 DLL 或 KERNEL32 获得 GP 故障请确保目标函数被声明为 _stdcall 和并不修改 DS、 ES、 完成-开始、 SS、 EBP、 EBX、 ESI 或 EDI 寄存器。C 或 c + + 代码应该不会导致修改,寄存器,但应该仔细检查汇编语言代码。
  6. 如果您基于 Win16 的目标函数将返回无效的位置请确保它在声明和定义为远处。这一点尤其重要的小模型 dll ; 默认情况下是远处中型和大型模型 dll 中的函数。
  7. 如果遇到了一个基于 Win16 的函数,当您访问多个数据从一个指针作为参数 (也就是一个 thunked 指针) 中传递的 64k GP 错误您需要分配一个数组的平铺的选择器,下面 Microsoft 知识库中相应的文章中所述:
    132005DOCERR: AllocSelector 和 FreeSelector 文档未完成
    Win16 侧 thunked 的指针总是包含单个选择器限制为这意味着您不能将它们用作巨大指针 64 K。但如果它创建一个数组的平铺的选择器,引用其,并且如果它使用访问数据的巨大的指针变量只在基于 Win16 的目标 DLL 的可访问整个原始区域的数据的指针地址。
  8. 请确保您只使用 thunked 的指针在 thunk 的上下文中。通过基于 Win16 的目标分配用于在 thunk 编译器的选择器的释放,只要在 thunk 返回。
  9. 将断点放在目标函数以确保所获取到它们的开头。如果您是,和已经调试目标端独立于 thunk,并且目标内部原因是,然后很好目标是执行某项不能在一个 thunk 中进行操作,或引用不存在的内存。请参阅第 7 和第 8 步。

属性

文章编号: 133722 - 最后修改: 2005年7月11日 - 修订: 2.3
这篇文章中的信息适用于:
  • Microsoft Platform Software Development Kit-January 2000 Edition?当用于
    • Microsoft Windows 95
    • Microsoft Windows 98 Standard Edition
    • Microsoft Windows Millennium Edition
关键字:?
kbmt kbhowto kbkernbase kbprogramming KB133722 KbMtzh
机器翻译
注意:这篇文章是由无人工介入的微软自动的机器翻译软件翻译完成。微软很高兴能同时提供给您由人工翻译的和由机器翻译的文章, 以使您能使用您的语言访问所有的知识库文章。然而由机器翻译的文章并不总是完美的。它可能存在词汇,语法或文法的问题,就像是一个外国人在说中文时总是可能犯这样的错误。虽然我们经常升级机器翻译软件以提高翻译质量,但是我们不保证机器翻译的正确度,也不对由于内容的误译或者客户对它的错误使用所引起的任何直接的, 或间接的可能的问题负责。
点击这里察看该文章的英文版: 133722
Microsoft和/或其各供应商对于为任何目的而在本服务器上发布的文件及有关图形所含信息的适用性,不作任何声明。 所有该等文件及有关图形均"依样"提供,而不带任何性质的保证。Microsoft和/或其各供应商特此声明,对所有与该等信息有关的保证和条件不负任何责任,该等保证和条件包括关于适销性、符合特定用途、所有权和非侵权的所有默示保证和条件。在任何情况下,在由于使用或运行本服务器上的信息所引起的或与该等使用或运行有关的诉讼中,Microsoft和/或其各供应商就因丧失使用、数据或利润所导致的任何特别的、间接的、衍生性的损害或任何因使用而丧失所导致的之损害、数据或利润不负任何责任。

提供反馈

 

Contact us for more help

Contact us for more help
Connect with Answer Desk for expert help.
Get more support from smallbusiness.support.microsoft.com