| Sav   
 Posts: 2180
 
 | 
			| 
 
				Частенько в коде Героев встречаются команды типа:lea eax, [eax + 8*eax]
 .
 
 Я правильно понимаю, что они нужны для упрощения написания вычислений (вместо:
 push ebx
 push edx
 mov ebx, eax
 mov edx, 0
 mov eax, 8
 mul ebx
 add eax, ebx
 pop edx
 pop ebx
 )?
 
 При выполнении есть ли разница между этими командами?
 
 
 И такой тупой вопрос: можно ли в Иде изменять команды не через Hex-view и как?
 |  | 
	| 04.10.2010 01:15 |  | 
	
		| etoprostoya   
 Posts: 1809
 
 | 
			| 
 
				Да, примерно так и есть. Разница очевидна - с командой LEA ты не изменяешь другие регистры и не работаешь со стеком.
			 |  | 
	| 04.10.2010 01:39 |  | 
	
		| Sav   
 Posts: 2180
 
 | 
			| 
 
				А когда процессор одинаково быстро выполняет эту lea-команду и "нормальный" код?
			 |  | 
	| 04.10.2010 01:48 |  | 
	
		| etoprostoya   
 Posts: 1809
 
 | 
			| 
 
				LEA-команды выполняются за один такт обычно или даже две-три такие команды за такт, а "нормальный код", который ты привёл, во много раз дольше, в лучшем случае в пять-десять раз.
			 |  | 
	| 04.10.2010 16:32 |  | 
	
		| Sav   
 Posts: 2180
 
 | 
			| 
 
				Но процессору всё равно же надо вычислить, чему равно,  eax+8*eax, он что, как-то по-особому вычисляет это в lea-команде?
			 |  | 
	| 04.10.2010 17:49 |  | 
	
		| etoprostoya   
 Posts: 1809
 
 | 
			| 
 
				Именно по-особому.К тому же в твоём "нормальном" примере изменяются три регистра, а значит их нельзя использовать в других командах, что замедляет выполнение программы (регистры-то часто используемые). Используется стек, то есть идёт обращение к кеш-памяти, на что отводятся дополнительные такты процессора, а в случае с полным кешем, этот кеш нужно выгружать в оперативную память (десятки тактов). Используются три подряд команды mov, что полностью блокирует на несколько тактов блок ввода-вывода, хотя это и не важно, так как дальше идёт длительная команда MUL. Эта команда MUL сама по себе плохая, особенно если в твоём случае блокирует использование сразу трёх регистров и все конвееры процессора или ядра останавливаются, ожидая завершения этой команды.
 
 А команда LEA специально оптимизирована для вычисления формул вида
 REG = REG+REG*2N+CONST.
 Современные процессоры вычисляют за такт несколько таких команд.
 |  | 
	| 04.10.2010 19:38 |  | 
	
		| Sav   
 Posts: 2180
 
 | 
			| 
 
				Тогда понятно и то, почему там eax+8*eax вместо 9*eax.Спасибо.
 |  | 
	| 04.10.2010 20:08 |  | 
	
		| ZVS   
   Posts: 500
 
 | 
			| 
 
				Если память мне не изменяет, то множители (2^N) могут быть только 2, 4 и 8. Этот модификатор команды появился только с i386. Ну и понятно, что умножение на 2^N суть сдвиг на N битов влево. Т.е. *9 и *8 две большие разницы (должно быть). Хотя современные процессоры и умножают уже за 1-2 такта.
			 |  | 
	| 05.10.2010 00:51 |  | 
	
		| etoprostoya   
 Posts: 1809
 
 | 
			| 
 
				 (05.10.2010 00:51)ZVS Wrote:  Если память мне не изменяет, то множители (2^N) могут быть только 2, 4 и 8. 
Ну, может быть и 1. То есть РЕГ = РЕГ + РЕГ. Ноль не считается.
 
Не знаю как самые-самые последние процессоры, но пару лет назад умножение было не меньше 3-4 тактов. Правда могло проходить сразу два умножения параллельно. Это про 32-разрядное умножение.
			 |  | 
	| 05.10.2010 14:03 |  | 
	
		| ZVS   
   Posts: 500
 
 | 
			| 
 
				РЕГ+РЕГ - это стандартный модификатор, который был еще в 80x86, а множители появились, начиная с i386 специально для быстрого обращения к элементам массивов.
			 |  | 
	| 05.10.2010 14:56 |  | 
	
		| Sav   
 Posts: 2180
 
 | 
			| 
 
				Может, кому-нибудь пригодится:
 по адресу [6919480]+1170n+137020, где n - номер героя,
 находится байт, в котором хранится 1, если герой спит (кнопка "Усыпить/разбудить героя" на карте приключений), иначе - 0.
 
				
(This post was last modified: 16.10.2010 17:02 by Sav.)
 |  | 
	| 16.10.2010 17:02 |  | 
	
		| SAG   
   Posts: 173
 
 | 
			| 
 
				 (01.09.2010 15:15)MOP Wrote:  Вот длл с более подробным (откомментированным) исходником. Создаёт триггер на лечение Палаткой. 
большая просьба прислать мне почтой на randommaps (@) yandex (.) ru.  ибо период полураспада файлообменников очень мал и сцылка уже нерабочая
			 |  | 
	| 24.10.2010 12:36 |  | 
	
		| Sav   
 Posts: 2180
 
 | 
			| 
 
				Вот исходник: 
LIBRARY Tent;{!INFO
 MODULENAME = 'Tent'
 VERSION = '1.0'
 AUTHOR = 'Master Of Puppets'
 }
 
 USES Win, Utils, SysUtils, VPUtils;
 
 //PROCEDURE HookCode(P: POINTER; NewAddr: POINTER; UseCall: BOOLEAN); external 'angel' name 'HookCode';
 
 CONST
 (* HookCode constants *)
 C_HOOKTYPE_JUMP = FALSE;
 C_HOOKTYPE_CALL = TRUE;
 C_OPCODE_JUMP = $E9;
 C_OPCODE_CALL = $E8;
 C_UNIHOOK_SIZE = 5;
 
 TYPE
 THookRec = RECORD
 Opcode: BYTE;
 Ofs: INTEGER;
 END; // .record THookRec
 
 VAR
 Temp: INTEGER;
 
 PROCEDURE WriteAtCode(P: POINTER; Buf: POINTER; Count: INTEGER);
 BEGIN
 Win.VirtualProtect(P, Count, PAGE_READWRITE, @Temp);
 Win.CopyMemory(P, Buf, Count);
 Win.VirtualProtect(P, Count, Temp, NIL);
 END; // .procedure WriteAtCode
 
 PROCEDURE HookCode(P: POINTER; NewAddr: POINTER; UseCall: BOOLEAN);
 VAR
 HookRec: THookRec;
 BEGIN
 IF UseCall THEN BEGIN
 HookRec.Opcode:=C_OPCODE_CALL;
 END // .if
 ELSE BEGIN
 HookRec.Opcode:=C_OPCODE_JUMP;
 END; // .else
 HookRec.Ofs:=INTEGER(NewAddr)-INTEGER(P)-C_UNIHOOK_SIZE;
 WriteAtCode(P, @HookRec, 5);
 END; // .procedure HookCode
 
 PROCEDURE HOOK_tent; ASSEMBLER; {$FRAME-}
 ASM
 MOV EAX, $50C7C0
 CALL EAX //вызываем функцию вычисления HP-очков, которую мы затёрли своим хуком.
 MOV DWORD PTR DS:[$91DA38],-1 //заносим в адрес переменной x1 значение -1 - на случай, если мы не хотим вообще ничего менять в принципе лечения
 MOV [$91DA3C], EAX //заносим в адрес переменной x2 исходное значение кол-ва хит-пойнтов, для подробностей и возможных вычислений
 PUSHAD //сохраняем регистры
 PUSH 29500 //номер ERM-функции. Меняйте на любой доступный.
 MOV EAX, $74CE30
 CALL EAX //вызываем C_FUNC_ZVS_CALLFU
 ADD ESP, 4
 POPAD //выталкиваем регистры
 CMP DWORD PTR DS:[$91DA38],-1 //проверяем, изменил ли скриптописец кол-во очков HP для лечения
 JE @@Default //если не изменил - продолжить код без изменения
 MOV EAX,DWORD PTR DS:[$91DA38] // заменить значение очков на значение из x1
 @@Default:
 PUSH $478538 //адрес возврата в процедуру
 END;
 
 BEGIN
 HookCode(POINTER($478533), @HOOK_tent, C_HOOKTYPE_JUMP);
 END.
Я уже отправил SAG-у файл на почту.
				
(This post was last modified: 24.10.2010 16:17 by Sav.)
 |  | 
	| 24.10.2010 15:50 |  | 
	
		| GhostManSD   
   Posts: 1054
 
 | 
			| 
 
				Подскажите, пожалуйста, как затереть/вызвать определенное диалоговое окно (алгоритм). Например, дабы вместо окна таверны вызывалось окно рынка.
			 
 Κακῆς ἀπ' ἀρχῆς γίγνεται τέλος κακόν.
 |  | 
	| 24.10.2010 21:48 |  | 
	
		| Дьякон   
 Posts: 395
 
 | 
			| 
 
				Элементарно. Менять таблицу jmp-ов для case - а идентификатора зданий.
			 
 Страус труп (с) Бьерн
 |  | 
	| 24.10.2010 22:57 |  |