Указатель Увеличение Разница B / W 32-битный и 64-битный
-
28-09-2019 - |
Вопрос
Я пытался запустить некоторые драйверы, закодированные для 32-битной Vista (x86) на 64-битном Win7 (AMD64), и он не работал. После многих отладки и удара и суда я сделал это, чтобы работать на последнем, но я не знаю причину, по которой это работает. Это то, что я сделал:
Во многих местах буферные указатели указывали на массив конструкций (разные в разных местах), а также для их увеличения, в некоторых местах использовался этот тип оператора:
ptr = (PVOID)((PCHAR)ptr + offset);
И в некоторых местах:
ptr = (PVOID)((ULONG)ptr + offset);
2-й один возвращал мусор, поэтому я изменил их все до 1-го. Но я нашел много образцов водителей в сети после второго. Мои вопросы:
- Где эти макросы определяются (Google не помог много)?
- Я понимаю, что все макросы P_ являются указателями, почему у указателя был указан в ueong? Как эта работа на 32-битной?
- PCHR очевидно, изменяет ширину в соответствии с окружающей средой. Вы знаете любое место, чтобы найти документацию для этого?
Решение
- они должны быть определены в Winnt.h (они находятся в SDK; не иметь DDK под рукой)
- Ulong не знает долго; На 32-битной системе это размер указателя. Таким образом, указатель может быть преобразован взад и вперед в ueong без потерь - но не так на 64-битной системе (где отличить значение, то будет урезать его). Люди отказываются от улонга, чтобы получить арифметику байта-байта (даже если это неопределенное поведение, как вы узнали)
- Указатель арифметики всегда работает в единицах базового типа, то есть в символах для PCHAR; Это приравнивает к арифметике байта
- Любая C-книга должна разработана на точной семантике указателя арифметики.
Другие советы
Причина, по которой этот код терпит неудачу на 64-битных, заключается в том, что он отличает указатели в Ulong. ULONG - это 32-битное значение, в то время как указатели на 64-битных являются 64-битными значениями. Таким образом, вы будете усекать указатель всякий раз, когда вы используете ueg Cast.
PCHAR CAST, предполагая 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 байта.
Макрос, которые вы упоминаете, используют отсюда, чтобы привести к коммутации адресов, которые они применяются к умножению на разные суммы. Это обычно делается только в низкоуровневом коде, который был передан буфером байта (или символа или пустоты), но знает данные внутри на самом деле какой-то другой тип.
ULONG
определяется в Windef.h в Windows SDK и всегда является 32-битным, поэтому, когда вы бросаете 64-битный указатель в ULONG
Вы обрезаете указатель на 32 бита.