Разница приращения указателя ч / б 32-битная и 64-битная - PullRequest
2 голосов
/ 25 ноября 2010

Я пытался запустить некоторые драйверы, написанные для 32-битной Vista (x86) на 64-битной win7 (amd64), и он не работал. После долгих отладок и пробных попыток я заставил их работать над последним, но я не знаю причину, почему это работает. Вот что я сделал:

Во многих местах указатели буфера указывали на массив структур (различающихся в разных местах), а для увеличения их в некоторых местах использовался такой тип оператора:

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

А в некоторых местах:

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

Второй возвращал мусор, поэтому я поменял их на первый. Но я нашел много примеров драйверов в сети после второго. Мои вопросы:

  1. Где эти макросы определен (Google не сильно помог)?
  2. Я понимаю, что все макросы P_ указатели, почему указатель был приведен ДОЛГО? Как это работает на 32-битный?
  3. PCHAR явно меняет ширина в соответствии с окружающей средой. Знаете ли вы, где найти документацию для этого?

Ответы [ 3 ]

3 голосов
/ 25 ноября 2010

Причиной сбоя этого кода на 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), но знает, что данные внутри него действительно другого типа.

3 голосов
/ 25 ноября 2010
  1. они должны быть определены в WinNT.h (они находятся в SDK; под рукой нет DDK)
  2. ULONG без знака долго; в 32-битной системе это размер указателя. Итак, указатель можно конвертировать обратно в ULONG без потерь - но не в 64-битной системе (где приведение значения будет усекать его). Люди приводят в ULONG, чтобы получить указатель на байтовую базу арифметика (даже если это имеет неопределенное поведение, как вы узнали)
  3. Арифметика указателя всегда работает в единицах базового типа, то есть в CHAR для PCHAR; это соответствует байтовой арифметике
  4. Любая книга на Си должна содержать точную семантику арифметики указателей.
1 голос
/ 25 ноября 2010

ULONG определяется в WinDef.h в Windows SDK и всегда является 32-разрядным, поэтому при приведении 64-разрядного указателя в ULONG вы усекаете указатель до 32-разрядного.

...