Сразу опишу смысл патча.
В стеке проги когда eip = 4B4071 имеем следующее:
esp + 0: arg4 ; аргумент 4 для последующего вызова функции.
Мне же надо сделать так:
esp + 0: arg4
esp + 4: myVal1 // мои параметры
esp + 8: myVal2 // для дальнейшего вызова моей функции через много команд
Естественно, esp переедет на 8 байт вниз.
Делаю патчик:
Код:
void _cdecl ecxfixup()
{
_asm
{
// here is shadow push ebx
mov [esp - 8], ebx
mov ebx, [esp + 4 + 4] // a4 for next call
mov [esp + 4 - 4], ebx
mov [esp + 4 + 4], ecx
mov ebx, [esp + 4]
mov [esp + 4 - 8], ebx
mov ebx, [esp - 8]
mov eax, [eax + 4]
mov [esp + 4], eax
lea esp, [esp - 4]
// restore killed commands
lea eax, [esi + 54h]
mov ecx, esi
ret
}
}
...
*((DWORD *)0x4B4071) = 0xE8; // call
*((DWORD *)0x4B4072) = (DWORD)&ecxfixup - 0x4B4076;
Как видно, тут мне пришлось все адреса в стеке сдвигать на 4, потому что студия, увидев, что ebx используется внутри кода, взяла и запушила его сама:
Код:
:001A42C0 loc_1A42C0:
:001A42C0 push ebx
:001A42C1 mov [esp-8], ebx
:001A42C5 mov ebx, [esp+8]
:001A42C9 mov [esp], ebx
:001A42CC mov [esp+8], ecx
:001A42D0 mov ebx, [esp+4]
:001A42D4 mov [esp-4], ebx
:001A42D8 mov ebx, [esp-8]
:001A42DC mov eax, [eax+4]
:001A42DF mov [esp+4], eax
:001A42E3 lea esp, [esp-4]
:001A42E7 lea eax, [esi+54h]
:001A42EA mov ecx, esi
:001A42EC retn
Но я-то ее не просил этого делать. Оно мне только мешает.
Вопрос: как в сях отключить автосохранение регистров при использовании асм-вставок? А то меня уже задолбало славливать баги в каждом третьем патче из-за того, что студия сама запушила регистр.
Самое интересное, что в каких-то случаях она НЕ сохраняет (по закону мерфи, конечно, не сохраняет только тогда, когда сохранять как раз надо).
З.Ы. суть в том, что один интерпретатор одного наркоманского скриптового языка имеет одно "замечательное" свойство: его разработчики забыли сделать обработку случая, когда функция возвращает строку. В этот момент интерпретатор падает с ошибкой. Я это пофиксил, добавив свой обработчик, но оптимизация интерпретатора убивает нужные мне значения, приходящие извне, в самом начале стандартного обработчика, а мой может вызваться только в конце работы стандартного. Спасает только вот такое вот решение.
И сохранять можно только в стеке, т.к. обработчики рекурсивные, рекурсия вызывается между убийством нужных значений и вызовом моего обработчика, следовательно, глобальные переменные не катят (они будут перезаписываться при каждой рекурсии).