В настоящее время я занимаюсь реконструированием игры, и я столкнулся с проблемой, когда мне нужно вызвать GetRawInputData
, который ожидает pcbSize
в качестве одного из своих аргументов.
Обычно на C я бы просто написал sizeof(pData)
, но я понятия не имею, как это сделать в машинном коде.
sizeof
является чисто конструкцией системы типа C и полностью преобразуется во время компиляции в простое число; в машинном коде такого нет, вы, вероятно, просто найдете немедленное значение в push
или mov
, соответствующее размеру pData
.
Например, в нашей программе последовательность
RAWINPUT raw;
UINT dwSize = sizeof(raw);
GetRawInputData((HRAWINPUT)lparam, RID_INPUT, &raw, &dwSize, sizeof(RAWINPUTHEADER));
переводится gcc 4.8 как
0x005f351d <+125>: lea eax,[ebp-0x48] // eax = &dwSize
0x005f3520 <+128>: mov DWORD PTR [esp+0xc],eax // pcbSize = eax = &dwSize
0x005f3524 <+132>: lea eax,[ebp-0x38] // eax = &raw
0x005f3527 <+135>: mov DWORD PTR [ebp-0x48],0x28 // dwSize = sizeof(raw) i.e. 38
0x005f352e <+142>: mov DWORD PTR [esp+0x10],0x10 // cbSizeHeader = sizeof(RAWINPUTHEADER) i.e. 16
0x005f3536 <+150>: mov DWORD PTR [esp+0x8],eax // pdata = eax = &raw
0x005f353a <+154>: mov DWORD PTR [esp+0x4],0x10000003 // uiCommand = RID_INPUT
0x005f3542 <+162>: mov DWORD PTR [esp],ecx // hRawInput = lparam
0x005f3545 <+165>: call DWORD PTR ds:0x20967fc // call GetRawInputData
Если это обычный массив C, он не изменяется во время выполнения. Если вместо этого это VLA, это совсем другая ситуация.
Значит, размер pdata всегда будет 13? Я обнаружил, что рядом с вызовом GetRawInputData, но в документации MSDN звучит так, будто значение изменится. Почему это вообще аргумент, если всегда будет 13?
@bcvdgfdagfewafdsaf: потому что они хотят иметь свободу действий для изменения размера / макета структуры в будущем. Затем со своей стороны они могут проверить размер, который был передан программой - если это старый размер, они знают, что это старая версия структуры, и заполняют ее соответствующим образом, если это новый размер, они заполняют ее всеми новыми Информация. Это общий шаблон для Win32 API (хотя обычно вы найдете член cbSize
прямо в структуре или что-то в этом роде). Кстати, я считаю маловероятным, что вы нашли размер 13 - RAWINPUT
намного больше (а 13 недостаточно выровнен)
вы правы, я смотрел в своем дизассемблере не на тот аргумент.
Нет никакого эквивалента. sizeof - это конструкция времени компиляции, она преобразуется только в число в сборке. Т.е. sizeof (pcbSize) будет примерно 48 или 1024 или так далее. Вы должны вычислить размер вручную или найти его в дизассемблированном коде, если он вам нужен.
В исходном коде сборка вы можете заставить ассемблер вычислять константы времени сборки, например
msg: db "hello world", 10 ; 10 = ASCII newline
msglen equ $-msg
Затем, когда вы пишете mov edx, msglen
, он собирается в mov edx, imm32
с подставленной константой. См. Некоторые примеры в Как именно $ работает в NASM?.
Но в окончательном машинном коде все константы времени ассемблирования стали непосредственными константами данных. (например, ptr_and_length: dq msg, msglen
в разделе data или rodata объединяется в адрес и целое число qword, которое есть только в объектном файле и не вычисляется во время выполнения из чего-либо.)
(Константы времени сборки также могут использоваться как счетчики повторов в макросах или других директивах (например,
).
times power imul eax, ecx
собирается в блок из такого количества инструкций imul
.
power
- это целочисленная константа, определяемая с помощью EQU. Или NASM %rep n
/ ... / %endrep
)
Или используется в выражениях времени ассемблера, так что сам размер буквально не присутствует в объектном файле, а является результатом некоторых вычислений, основанных на нем. (например, mov edx, msglen+2
или mov ecx, arrbytes/4
, последнее может быть связано с циклом, который считается по двойным словам вместо байтов).
Если это правда, как sizeof возвращает размер данных, размер которых может измениться во время выполнения?