2

我试图在 64 位 win7 (amd64) 上运行一些为 32 位 vista (x86) 编码的驱动程序,但它没有运行。经过大量的调试和反复试验,我让它在后者上工作,但我不知道它工作的原因。这就是我所做的:

在许多地方,缓冲区指针指向一个结构数组(在不同的地方不同),为了增加它们,在某些地方使用了这种类型的语句:

ptr = (PVOID)((PCHAR)ptr + offset);

在某些地方:

ptr = (PVOID)((ULONG)ptr + offset);

第二个是退回垃圾,所以我把它们都换成了第一个。但是我在第二个之后在网上找到了许多示例驱动程序。我的问题:

  1. 这些宏在哪里定义(谷歌没有多大帮助)?
  2. 我知道所有 P_ 宏都是指针,为什么将指针转换为 ULONG?这在 32 位上如何工作?
  3. PCHAR 显然会根据环境改变宽度。你知道有什么地方可以找到这方面的文件吗?
4

3 回答 3

3
  1. 它们应该在 WinNT.h 中定义(它们在 SDK 中;手头没有 DDK)
  2. ULONG 是无符号长;在 32 位系统上,这是指针的大小。因此,指针可以来回转换为 ULONG 而不会丢失 - 但在 64 位系统上则不然(转换值会截断它)。人们转换为 ULONG 以获得基于字节的指针算术(即使这具有未定义的行为,正如您所发现的)
  3. 指针运算总是以底层类型为单位工作,即在 PCHAR 的 CHAR 中;这相当于字节算术
  4. 任何 C 书籍都应该详细说明指针算术的精确语义。
于 2010-11-25T13:18:11.470 回答
3

此代码在 64 位上失败的原因是它正在将指针转换为 ULONG。ULONG 是 32 位值,而 64 位上的指针是 64 位值。因此,每当您使用 ULONG 强制转换时,您都会截断指针。

PCHAR 强制转换,假设 PCHAR 被定义为char *很好,前提是目的是将指针增加一个明确的字节数。

这两个宏具有相同的意图,但只有一个在指针大于 32 位时有效。

指针算术是这样工作的。如果你有:

T *p;

你也是:

p + n;

(其中 n 是一个数字),那么 p 的值将改变n * sizeof(T).

举一个具体的例子,如果你有一个指向 DWORD 的指针:

DWORD *pdw = &some_dword_in_memory;

然后你添加一个:

pdw = pdw + 1;

那么您将指向下一个 DWORD。pdw 指向的地址将增加sizeof(DWORD)4 个字节。

您提到的宏使用强制转换导致它们应用的地址偏移量乘以不同的数量。这通常只在已传递 BYTE(或 char 或 void)缓冲区但知道其中的数据实际上是其他类型的低级代码中完成。

于 2010-11-25T13:24:11.090 回答
1

ULONG在 Windows SDK 的 WinDef.h 中定义并且始终为 32 位,因此当您将 64 位指针转换为ULONG您将指针截断为 32 位时。

于 2010-11-25T14:03:47.920 回答