Алексей
Где кошачья мята?!
offline
Опыт:
26,543Активность: |
War: взгляд изнутри.
WAR: ВЗГЛЯД ИЗНУТРИ
Вот давно обещанная статья по «внутренностям» War’а. Она предназначена для программистов-модмейкеров и рассказывает, как организовать взаимодействие War’а с внешней программой.Конечный продукт
Чтобы не отнимать время у всех читателей-непрограммистов, я сразу начну с готовых программ, а потом уж приступлю к их разбору.Итак, первый из написанных мной «модов» к War’у – программа waradd.exe (лежит в архиве waradd.zip). Она позволяет отслеживать позицию курсора мыши в War’е. Просто скопируйте её в папку с War’ом и запустите. При этом War запустится автоматически. В том же архиве лежит пример карты, использующей эту программу. После запуска карты на экране выводится позиция курсора мыши (триггер срабатывает каждые 0,5 сек). Как это работает? Прежде всего, в редакторе триггеров необходимо объявить переменную целочисленного типа. Она может идти под любым именем, но должна равняться 98765432. Мод сканирует память War’а, и, найдя это число, начинает записывать туда позицию курсора мыши (в «сжатой» форме = Y*65526+X). . Вторая программка предназначена для тех модмейкеров, которые хотят дополнить War собственным MPQ-архивом. Вроде бы такие архивы замещают файл war3patch.mpq. Я всегда считал абсурдной эту идею – чтобы War не вылетал после такой операции, необходимо положить в новый MPQ кучу всякого хлама (у меня при попытке перезаписи этого файла War и WE начинали вылетать). И даже существуют программы, которые на время запуска заменяют war3patch.mpq “модовским” архивом, а после выхода из War’а – восстанавливают исходный архив. Тут есть одно НО: современные компьютеры иногда виснут. И если War повиснет, когда war3patch.mpq перезаписан, то потом мод уже не запустится, а сам War начнёт глючить. Идеальным решением было бы научить War вместо war3patch.mpq «заглатывать» нечто иное – безо всякой перезаписи и переименования файлов. Итак, в архиве warmod.zip лежат две программки – warmod.exe и newWE.exe. Их опять-таки нужно скопировать в каталог с War’ом. При запуске первой из них запустится War, но вместо war3patch.mpq он будет пытаться загрузить war3mod.mpq. При запуске второй запустится WE, и тоже будет грузить war3mod.mpq. . Продолжаем! Что нужно для работы?
Для работы нам понадобятся:
. Акт 1: Запуск War и «отлов» событий
Начнём с того, что напишем программу, запускающую War и отслеживающую некоторые события, происходящие внутри него. (Готовый пример лежит в каталоге Ex1 архива exs.zip). Ни для кого не секрет, что сам «движок» War’а заводится при запуске файла war3.exe. Все остальные экзешники – это лишь обёртки, выбирающие режим его работы. Если запустить просто war3.exe, то War запустится как TFT. На Delphi запуск War’а реализуется так:Код:
Кстати, такой способ контроля посторонней программы используется всеми отладчиками. И теперь наша программа получает возможность вызывать особые «отладочные» функции (Debug API) для управления запущенным процессом. Далее мы просто ждём наступления какого-либо отладочного события: Код:
Стоп, всё не так просто! Оказывается, существует ещё одно, совершенно особое исключение – EXCEPTION_BREAKPOINT. При его первом возникновении нужно использовать DBG_CONTINUE, а во все последующие разы – DBG_EXCEPTION_NOT_HANDLED. . Что ж, вся теория позади, переходим к практике. Напишем программу, которая будет отслеживать создание/удаление потоков War’а и выводить их количество в файл zz.txt. В общем, пускаем War, затем создаём наш лог: Код:
Далее начинаем обрабатывать отладочные события. Обработка организована в виде цикла: Код:
Код:
Код:
Теперь перейдём к обработке исключений. Их мы тоже будем отмечать в логе – за исключением сакраментального EXCEPTION_BREAKPOINT: Код:
Ну, вроде всё. Компилируем, пускаем (только не из-под Delphi! Он сам содержит отладчик и будет конфликтовать с нашей программой. Поэтому компилируем её по Ctrl+F9, копируем в папку с War’ом и запускаем). По окончании игры смотрим листинг. Основной результат такого исследования состоит в том, что War в момент запуска создаёт 19 потоков, а затем их только использует! Большинство потоков висят замороженными, и «размораживаются» по мере надобности. Взамен каждого подвисшего потока тотчас создаётся новый. Кстати, на самом деле потоков 20, а не 19 – т.к. создание главного потока фиксируется событием CREATE_PROCESS_DEBUG_EVENT, а его мы не обрабатывали. . Акт 2: ищем триггерную переменную
Теперь усложним нашу программу – сделаем так, чтобы она искала в недрах War’а нужную нам переменную и выводила в лог её адрес. Готовый исходник лежит в Ex2.Прежде всего, цикл ожидания событий вынесен в отдельную процедуру - ProcessEvents. Там же содержится проверка – а не завершился ли War. И если завершился, выходим: Код:
Код:
Код:
Итак, начало программы – стандартное: пускаем War, создаём лог-файл… А дальше выдерживаем 7-секундную паузу (ждём события): Код:
Прежде всего получаем информацию об очередном блоке памяти: Код:
Код:
Код:
Код:
Код:
Итак, процедура сканирования памяти готова, пауза 7 сек. выдержана, самое время приступить к сканированию! Оно будет проводиться каждые 2 сек (чтобы не занимать ресурсы) до нахождения переменной: Код:
Код:
Код:
Код:
Кроме того, в том же каталоге появится небольшой файл дампа области переменных (обычно не более 100Кб). Он обладает двоичной структурой, и анализировать его можно только в HEX-редакторе (я предпочитаю HexEd, т.к. он идёт в комплекте RadASM, небольшой по размеру и совершенно бесплатен). . Акт 3: передаём данные в War
Открываем каталог Ex3 и смотрим исходник. От Ex2 он отличается только тем, что в найденную переменную мы пишем некое число:Код:
. Акт 4: надёжный поиск .Анализ дампов памяти, созданных предыдущими примерами, показал, что каждая целочисленная переменная занимает целых 40 байт памяти, лишь 4 из которых содержат число. Ещё 8 указывают тип переменной. Например, целочисленный тип описывается так: 04 00 00 00 – 04 00 00 00 Т.е. теперь мы можем повысить надёжность поиска, не только сканируя память на указанное число (мало ли, где оно может встретиться?), но ещё и проверяя тип переменной. Кроме того, вы, вероятно, были в некотором недоумении – почему число 98765432 в виде строки представлено как #120#10#227#05 ? А если вам хочется использовать другой шаблон поиска, что тогда? Или если нужно записывать что-то сразу в несколько переменных, ведь им нельзя присваивать одинаковые значения… Поэтому открываем каталог Ex4 и смотрим. Новая программа отличается от Ex3 лишь небольшими изменениями процедуры MemScan. Теперь она принимает не строку, а сразу ЧИСЛО, которое нужно найти в памяти. Строку из него она формирует самостоятельно, да ещё и дополняет её типом переменной для более надёжного поиска. Для этого там прежде всего объявляется константная строка, содержащая тип переменной: Код:
Код:
Код:
. Акт 5: Наконец-то добрались до курсора!
Ну, теперь уже можно приступить к отслеживанию курсора мыши (не прошло и полугода…). Готовый пример находится в каталоге Ex5. Прежде всего, убираем все строки кода, связанные с созданием и ведением логов (в самом деле, зачем они нам теперь-то?). И – после нахождения переменной каждые 40мс будем записывать туда позицию курсора мыши (в сжатой форме):Код:
. Акт 5а: это реально!
От целочисленных переменных переходим к реальному типу. Возможно, вам интересно, как можно находить «реальные» переменные и чего-либо в них записывать. Готовый пример находится в каталоге Ex5. Эта программа напоминает Ex3, т.е. ничего не отслеживает, а только находит переменную со значением 123.45 (удобный шаблон, не правда ли?) и заменяет её на 11.11. Прежде всего, анализ дампов памяти показал, что реальный тип в War’е обозначается как05 00 00 00 – 05 00 00 00 и соответствует Delphi’шному типу single. Соответственно, он конвертируется в строку… И всё – аналогично предыдущим примерам. См. исходник. Да, кстати, карта zzz.w3m для тестирования этого примера не подходит, т.к. она пользуется только целочисленными переменными. Поэтому в том же каталоге находится карта real.w3m (содержит переменную с шаблоном и выводит на экран её значение). . Акт 6: это только начало…
Вы думаете, всё так просто? Ха-ха! Как вы считаете, что произойдёт, если игрок выйдет в главное меню War’а или загрузит новую карту? Ведь мы каждые 40мс пишем координаты курсора в найденную переменную, а при выходе из карты освободившаяся память занимается War’ом под что-то другое. И не факт, что даже перезапуск карты оставит переменную на том же месте! Т.е. при перезапуске карты или выходе из неё War может та-ак глюкануть… Вывод: для безглючной работы программы жизненно необходимо отслеживать момент выгрузки карты и начинать сканирование сызнова.Это непросто, но что делать… Основная проблема – поймать момент «выгрузки» карты. Я перебрал несколько вариантов и остановился на следующем. 1. Ставим на нашу переменную ТОЧКУ ОСТАНОВА. 2. Как только War попытается занять эту память под что-то другое, она сработает (возникнет исключение), и мы поймём, что нужно сканировать заново. Что такое точки останова, программисту объяснять не нужно – любой отладчик (тот же Delphi) умеет их ставить. А теперь мы сами выступаем в роли отладчика и будем расставлять точки останова в War’е. Главная проблема заключается в том, что точка останова действует только в контексте потока. Т.е. нам нужно будет ставить точки останова на каждый поток War. Вот теперь-то нам их список и пригодится. Кстати, главный поток теперь тоже отлавливается: Код:
Код:
Код:
Код:
Код:
Если вы пишете что-то в несколько переменных, достаточно поставить точку останова лишь на одну из них – все остальные находятся в том же блоке памяти. Более того: так можно сильно ускорить поиск. Если в блоке найдена одна из переменных, то все остальные нужно искать там же, а не просматривать всю память с самого начала. Ну разве это не круто? . Часть II: ЗАТОЛКАТЬ ДРЯНЬ
Да, теперь мы напишем программу, при запуске которой War (и WE) вместо файла war3patch.mpq будут грузить War3mod.mpq. Боюсь, правда, что подобный «мод» представляет исключительно теоретический интерес, т.к. мне ещё не встречались случаи замены War’овских MPQ самопальными.Этот таинственный ассемблер
Ну вот, к этому моменту все читатели уже разбежались (или уснули) :end:, так что самое время пускать в ход тяжёлую артиллерию. Держитесь крепче: эту программу мы напишем на чистом ассемблере! Причём сделаем её универсальной – достаточно поменять пару строк, и она будет запускать программу X, отслеживать обращения к файлу Y и перенаправлять их на файл Z.Вначале немного об ассемблере. Не бойтесь – в нём нет ничего страшного. Современный ассемблер – это уже не тот монстр, который ещё 10 лет назад был кошмаром любого программиста. [Одна линковка чего стоила, с бесконечным подбором многочисленных ключей…] Теперь это – довольно простой язык, во всяком случае, не сложнее Си. Более того: ассемблер – самый доступный язык программирования. Достаточно закачать 780Кб (бесплатный пакет!) – и у вас в руках будет средство, способное создавать программы для DOS/Windows/Linux/BeOS/MeOS, obj-файлы, драйвера всех видов и под любые x86-процессоры (16/32/64-разрядные); всякие специфические штучки (бут-сектора, программы BIOS и пр.). Если же у кого-то проблемы с трафиком, можно закачать уменьшенный пакет (150Кб, без редактора – только компилятор и набор включаемых модулей). Почему же asm’ом так редко пользуются? Первая и основная причина – практически полное отсутствие документации. Ну вот не привлекает он почему-то внимания авторов книг серии «для чайников». Если в комплекте со всеми остальными языками и средами разработки идёт здоровенный HELP (который подчас весит больше всего остального), то для asm’а ничего такого не предусмотрено. Согласитесь, что «методом тыка» изучить даже самый простой язык невозможно. В сети нормальной инфы тоже нет – сведения приходится собирать буквально по крупицам. Их основным источникам служат всё те же Microsoft SDK/DDK, AMD Architecture Programmer’s manual (вроде бы есть ещё аналогичный мануал от Intel, но я его не нашёл) и, конечно, ассемблерные исходники. Ещё одна проблема – чуть повышенное время разработки (написание программы на asm’е отнимает примерно на 10-15% больше времени, чем на Си). Впрочем, эти недостатки окупаются исключительной миниатюрностью программ: простейшие «безоконные» программы занимают около 2Кб, а программы, имеющие собственное окошко – 4Кб. Разумеется, это минимальные цифры – чем больше функциональность, тем больше и вес. Но всё равно он будет значительно меньшим, чем у Delphi-приложений. Более того: даже эти миниатюрные программы легко сжимаются архиваторами (в zip-архиве - примерно вдвое). . Так что открываем каталог ExMod и смотрим… А там есть целых 3 файла. Причём 2 из них стандартные:
Ну ладно. Прежде чем лезть в дебри ассемблерного кода, разберём собственно алгоритм – как можно заставить War заглотить «не тот» архив. Всё просто: прежде чем работать с файлом, его нужно открыть. War открывает файлы с помощью функции CreateFileA. Всё, что нам нужно сделать – отследить вызов этой функции, проверить её параметры, и если имя открываемого файла равно war3patch.mpq, заменить его на war3mod.mpq. И всё! Теперь о том, как отследить вызов нужной функции. Самый простой метод – сплайсинг, но он не годится для локального перехвата (т.е. сплайсингом мы перехватим вызов функции ВСЕМИ процессами Windows, что нам совершенно не нужно). Поэтому воспользуемся другим способом. Он тоже довольно прост: ставим точку останова на функцию, и когда она сработает – смотрим, что там с параметрами. Как уже говорилось ранее, точки останова должны ставиться на каждый поток индивидуально, поэтому ничего лишнего мы не затронем. Тут, правда, есть одна проблема: в предыдущем примере точки останова удалялись нами сразу после их срабатывания. Здесь так поступить нельзя – точка должна висеть всё время работы War’а, т.к. он в любой момент может «связаться» с MPQ. Поэтому нам придётся заставлять War «проскакивать» точки останова (т.е. заставить его всё-таки выполнить функцию с изменёнными параметрами, несмотря на то, что точка по-прежнему стоит). Делается это так:
Ну, любая программа начинается с заголовка, и ассемблерная – не исключение. В заголовке указывается, под какую ОС мы будем компилировать программу, под какой процессор и что это вообще за программа (библиотека, драйвер, линкуемый файл, простой exe-файл и т.д.). Там же указывается точка входа (т.е. позиция, с которой начнётся выполнение программы). Далее подключаются необходимые файлы (директивой include). Напоминает Си, не правда ли? В самом конце программы я объявляю все необходимые переменные (хотя их можно объявить в любом месте программы). ASM может работать с виртуальными переменными (память под них выделяется динамически), чем я и пользуюсь: Код:
Итак, в начале программы провожу всевозможную инициализацию. В частности, помещаю 0 в ebx (зачем – объясню позже), выделяю память под виртуальные переменные и очищаю её (забиваю нулями). Код:
Код:
Код:
Теперь – пускаем War. Это осуществляется всё той же функцией CreateProcess: Код:
Итак, War запущен. Теперь начинаем обрабатывать события: Код:
Далее идёт анализ событий. Прежде всего, отслеживается создание потоков. Хэндлы всех созданных потоков собираются в массиве hWarThreads: Код:
Код:
Код:
Код:
Код:
Теперь анализируем событие типа EXCEPTION_DEBUG_EVENT. Прежде всего, если это исключение типа EXCEPTION_BREAKPOINT, то продолжить выполнение процесса (используя флаг DBG_CONTINUE): Код:
Код:
Код:
Код:
Код:
Код:
Вот, в принципе, и всё – далее идут лишь всякие «обёртки» цикла и завершение программы. Как видите, всё не так уж сложно. Компилируем программу… И видим, что её размер равен 2Кб! (Кстати, размер программы всегда округляется asm’ом до величины, кратной 512 байтам). . Так, вижу, я остался в гордом одиночестве – все читатели уже потерялись. Что ж, пойду и я… :end: |
03.04.2006, 13:37 | #1
+0/−0
Профиль |
Приват |
Поиск |
IP: Записан
|
PotioN
offline
Опыт:
1,204Активность: |
Действительно, такое написать не каждый способен. |
03.04.2006, 15:28 | #2
+0/−0
Профиль |
Приват |
Поиск |
IP: Записан
|
zibada
offline
Опыт: отключен
|
да... 5 баллов.
кстати, если продолжить тему слежения за варом снаружи...
есть идея, как написать 100% надежный генератор листфайлов карт и других mpq-архивов без брутфорса, поиска имен по файлам карты и т.д. идея проста: каким-то образом перехватывать все вызовы варом функций открытия файла по имени (SFileOpenFile и SFileOpenFileEx вроде) из storm.dll и дампить передаваемые имена файлов в лог. тогда получение листфайла сведется к тому, что достаточно запустить с этой прогой-перехватчиком карту и немного ее погонять, чтобы гарантированно задействовать все файлы из нее =) (если какие-то останутся неиспользованными, можно предположить, что они нафиг не нужны) если кто-то такое напишет, это будет замечательно, моего скромного опыта, боюсь, на такие раскопки не хватит... |
03.04.2006, 16:47 | #3
+0/−0
Профиль |
Приват |
Поиск |
IP: Записан
|
NETRAT
offline
Опыт:
83,762Активность: |
DimonT На самом деле подобного рода мегалоги займут очень много времени, когда я копался со Storm.dll заметил такую фигню что при большой частоте запросов она часто отвечает отказом, то есть просто пропускает файлы. Не вижу смысла отлавливать эти события ибо MPQ Recover делает то же самое - проверяет наличие файлов, к которым вар МОЖЕТ обращаться. Только описанный глюк делает саму программу чутка глючной, особенно это заметно при брутфорсе - это почти нереально
|
03.04.2006, 18:23 | #4
+0/−0
Профиль |
Приват |
Поиск |
IP: Записан
|
Sir Lothar
offline
Опыт:
5,740Активность: |
Алексей, моё тебе уважение. Хоть я в программировании, к сожалению, ничего и не смыслю, но вижу, что статья замечательная.
|
03.04.2006, 19:31 | #5
+0/−0
Профиль |
Приват |
Поиск |
IP: Записан
|
Nomad
offline
Опыт:
6,677Активность: |
Ничерта не понял, но всё равно класс! :D |
03.04.2006, 21:01 | #6
+0/−0
Профиль |
Приват |
Поиск |
IP: Записан
|
NETRAT
offline
Опыт:
83,762Активность: |
Алексей Andrew II не так давно спрашивал как запихнуть между архивами еще один, что ты думаешь по этому поводу? Мне бы тоже было интересно возможно ли war3patch переписать сверху своим архивом, то есть дополнить его...
[Кстати, надо бы повесить глобальный хук на ShellExecute и поймать параметры коммандной строки вара когда мы запускаем его из WE - может там чего интересного есть] По поводу сплайсинга - мы же можем определить модуль, который был перехвачен и отсеять варовские библиотеки - то есть, кажется, тут все будет работать, разве что перехват будет проходить чаще Алексей, а разве нам обязательно запускаться из-под дебаггера? Работать с памятью - выставить разрешения и работать вроде бы можно из обычного процесса, проблема вроде бы в другом - найти дескриптор процесса вара и отследить блок памяти в котором он запустился... Погодь, а почему вар открывает файлы с помощью CreateFile? Почему не OpenFile(Ex)? Цитата:
Цитата:
Жаль что для многих ассемблер это всего лишь непонятные слова на три буквы =\ NETRAT добавил: Поэтому-то меня больше интересует High-Level - потому что так глубоко в Low-Level я залезть не смогу - на это нужно намного больше времени и сил |
||
04.04.2006, 01:56 | #7
+0/−0
Профиль |
Приват |
Поиск |
IP: Записан
|
Алексей
Где кошачья мята?!
offline
Опыт:
26,543Активность: |
Думаю, что можно, хотя придётся постараться. Для этого нужно:
1. Самостоятельно открыть новый архив (с помощью storm.dll) 2. Отслеживать открытие файла, находящегося в недрах MPQ. 3. Пробовать открыть этот файл в новом MPQ. Если он там есть - возвращать его данные, иначе - передавать управление стандартной SFileFileOpen. 4. По окончании работы - закрыть архив. . Далее - WE вроде бы не запускает War. Зачем? Разве что когда карту тестируешь... Насчёт сплайсинга - да, можно отследить модуль, и всё будет работать. Вероятно, код был бы даже проще, нагляднее и компактнее. Но программы, пользующиеся сплайсингом, труднее отлаживать - при любой ошибке неторопливо падает вся система (думаю, тебе тоже приходилось испытывать эти незабываемые ощущения ;)). А при неверном использовании Debug API - падает только отлаживаемый процесс. Почему нельзя пустить War как независимый процесс? Ну, а как тогда отследить отвобождение памяти (перезагрузку карты)? А так - ставим точку останова и ждём... . Разумеется, War не использует OpenFile. В Microsoft SDK написано: "Эта функция оставлена для совместимости с ранними версиями Windows. Использовать её не рекомендуется. Используйте CreateFile для открытия файла". . Сколько какие команды занимают - это описано в "AMD x86 Code Optimization Guide". Там вообще неплохо описано, как оптимизировать ассемблерный код. Между прочим, учёт особенностей процессоров помогает и при программировании на языках высокого уровня. Вот классический пример: объяснить, почему цикл Код:
Код:
|
04.04.2006, 10:57 | #8
+0/−0
Профиль |
Приват |
Поиск |
IP: Записан
|
NETRAT
offline
Опыт:
83,762Активность: |
Да, забавно, шелл намертво подвисает и потихоньку начинают отказывать службы. Просто даун =)
Просто с помощью такой утилиты можно значительно сьэкономить место засчет того что лишних файлов в установочном MPQ мода не будет
Мда, мне нужно время чтобы это обдумать... |
04.04.2006, 11:58 | #9
+0/−0
Профиль |
Приват |
Поиск |
IP: Записан
|
exploder
iOS zealot
offline
Опыт:
19,394Активность: |
Автору респект зп подробную и простую статью... |
04.04.2006, 21:29 | #10
+0/−0
Профиль |
Приват |
Поиск |
IP: Записан
|
Iron
Листовой
offline
Опыт:
23,587Активность: |
Это ппц, все какие-то сплошные программеры ...
Каким-то неполноценным идиотом себя чуствуешь. Все, складываю шмот и мотаю с xgm-а. |
05.04.2006, 01:11 | #11
+0/−0
Профиль |
Приват |
Поиск |
IP: Записан
|
NETRAT
offline
Опыт:
83,762Активность: |
На самом деле их не так уж и много, но хотелось бы больше |
05.04.2006, 01:25 | #12
+0/−0
Профиль |
Приват |
Поиск |
IP: Записан
|
Toadcop
offline
Опыт:
53,013Активность: |
Алексей спасибо ! буду изучать :) статья объемная это хорошо !
|
05.04.2006, 17:58 | #13
+0/−0
Профиль |
Приват |
Поиск |
IP: Записан
|
Mefist
Is it cocktail hour yet?
offline
Опыт:
98,240Активность: |
я статью не читал, но нетра или алексей, как посчитаете ее готовой - кидайте на сайт |
05.04.2006, 18:08 | #14
+0/−0
Профиль |
Приват |
Поиск |
IP: Записан
|
NETRAT
offline
Опыт:
83,762Активность: |
Вполне готова, я немного не успеваю |
05.04.2006, 19:35 | #15
+0/−0
Профиль |
Приват |
Поиск |
IP: Записан
|
exploder
iOS zealot
offline
Опыт:
19,394Активность: |
Можно чем извращатся и делать инвентари варовскими методами, можно отслеживать мышь (для того чтобы узнать действия над инвентарем), а сам инвентарь рисовать прямо по Варовскому контексту :)= Единственное гавны так это что необходимо будет много переменных для общения прога-варик и синхронизация прорисовки своих графических элементов и прорисовки сцены в Варе... |
07.04.2006, 08:18 | #16
+0/−0
Профиль |
Приват |
Поиск |
IP: Записан
|
N.Sy.Prophet
Йа Байан
offline
Опыт:
13,122Активность: |
Цитата:
истину глаголишь :) |
|
08.04.2006, 19:31 | #17
+0/−0
Профиль |
Приват |
Поиск |
IP: Записан
|
NETRAT
offline
Опыт:
83,762Активность: |
Статья добавлена по ссылке http://xgm.guru/articles.php?section=wc3&name=inside_of_warcraft
|
08.04.2006, 21:31 | #18
+0/−0
Профиль |
Приват |
Поиск |
IP: Записан
|
Toadcop
offline
Опыт:
53,013Активность: |
Код:
for (a=0; a<BLOCK_SIZE; a+=8*sizeof(int)) { x+=*(int *)((int)p+a); x+=*(int *)((int)p+a+1*sizeof(int)); x+=*(int *)((int)p+a+2*sizeof(int)); x+=*(int *)((int)p+a+3*sizeof(int)); x+=*(int *)((int)p+a+4*sizeof(int)); x+=*(int *)((int)p+a+5*sizeof(int)); x+=*(int *)((int)p+a+6*sizeof(int)); x+=*(int *)((int)p+a+7*sizeof(int)); }работает вдвое быстрее конструкции Код:
for (a=0; a<BLOCK_SIZE; a+=sizeof(int)) { x+=*(int *)((int)p+a); } интересно... да кстати я на асемблере не писал но не уж такой и сложный и мне нравитьса что он компактный :)
ЗЫ где можно компилятор закачать и малинький хелп ?! :) был бы очень благодарен ! ЗЫ статья очень интересная !!! |
09.04.2006, 16:28 | #19
+0/−0
Профиль |
Приват |
Поиск |
IP: Записан
|
Markiz
offline
Опыт:
11,392Активность: |
Статья - супер! Я почитал пока только процентов 50, но готов оценить статью на 100 из 100 баллов. Дочитаю и буду просматривать внутренности вара. |
09.04.2006, 17:41 | #20
+0/−0
Профиль |
Приват |
Поиск |
IP: Записан
|