Из этой статьи ты узна­ешь нес­коль­ко трю­ков, которые помогут тебе сок­ращать раз­мер ассем­блер­ных прог­рамм. Попут­но оку­нешь­ся в нас­тро­ение «Клу­ба модели­рова­ния желез­ной дороги» Мас­сачусет­ско­го тех­нологи­чес­кого инсти­тута, где такие трю­ки в свое вре­мя ценились осо­бен­но высоко.
 

Резьба по ассемблерному коду

На­деюсь, ты зна­ешь кни­гу Сти­вена Леви «Хакеры: герои компь­ютер­ной револю­ции». Если нет, обя­затель­но проч­ти! Сей­час мы с тобой понос­таль­гиру­ем по тем слав­ным вре­менам, которые опи­сыва­ет Леви. В час­тнос­ти, вспом­ним, чем пионе­ры хакерс­тва занима­лись в «Клу­бе модели­рова­ния желез­ной дороги» Мас­сачусет­ско­го тех­нологи­чес­кого инсти­тута и как они кодили.

Ха­керы тех вре­мен, кор­пя над сво­ими прог­рамма­ми, пытались выжать из ассем­блер­ных инс­трук­ций все, что толь­ко воз­можно, что­бы в ито­ге прог­рамма ста­ла мак­сималь­но ком­пак­тной. Попыт­ки отре­зать часть инс­трук­ций от компь­ютер­ной прог­раммы без воз­дей­ствия на конеч­ный резуль­тат ста­ли для хакеров навяз­чивой иде­ей.

Иног­да такая резь­ба по ассем­блер­ному коду при­нима­ла сос­тязатель­ный харак­тер — сво­еоб­разное сорев­нование мачо, приз­ванное доказать себе и дру­гим, что совер­шенс­тву нет пре­дела. Ты отре­зал две инс­трук­ции или даже одну? Получи бур­ные апло­дис­менты брать­ев по духу. Ты перес­мотрел проб­лему с нуля, с неожи­дан­ного угла зре­ния и раз­работал новый алго­ритм, который сок­ратил прог­рамму на целый блок команд? Испы­тай катар­сис и получи еще более бур­ные апло­дис­менты!

Осо­бое рве­ние хакеры про­явля­ли к опти­миза­ции под­прог­раммы для печати десятич­ных чисел. За нес­коль­ко месяцев они изго­тови­ли целую кучу вари­аций. С чего вдруг такой инте­рес имен­но к этой задаче?

С того, что в MIT дей­ство­вало нег­ласное пра­вило: «Если ты собс­твен­норуч­но написал под­прог­рамму печати десятич­ных чисел, зна­чит, зна­ешь о компь­юте­ре дос­таточ­но, что­бы называть себя в некото­ром роде прог­раммис­том. При­чем, если у тебя ушло на эту под­прог­рамму око­ло сот­ни ассем­блер­ных инс­трук­ций, зна­чит, ты бес­прог­лядный глу­пец, хотя и прог­раммист. А если написал дей­стви­тель­но хорошую и корот­кую про­цеду­ру мень­шего раз­мера, то можешь поп­робовать называть себя хакером».

В конеч­ном сче­те, попере­мен­но уби­рая инс­трук­ции то в одном, то в дру­гом мес­те, хакеры допили­ли про­цеду­ру печати десятич­ных чисел до пятиде­сяти с неболь­шим инс­трук­ций.

Даль­ше дело при­няло серь­езный обо­рот. Поиск луч­шего решения прев­ратил­ся в неч­то боль­шее, чем прос­то сос­тязание, — в поиск свя­того Гра­аля. Одна­ко, сколь­ко бы сил ни было пот­рачено, никому не уда­валось пре­одо­леть барь­ер из пятиде­сяти команд. И ког­да прак­тичес­ки все уже сми­рились с тем, что это невоз­можно, один из хакеров догадал­ся пос­мотреть на решение задачи под дру­гим углом. В ито­ге его вер­сия под­прог­раммы умес­тилась в 46 ассем­блер­ных инс­трук­ций.

До это­го зна­мена­тель­ного часа все счи­тали, что опти­маль­ный алго­ритм для под­прог­раммы печати десятич­ных чисел — это пос­ледова­тель­ное вычита­ние, при котором исполь­зовались таб­лицы сте­пеней чис­ла 10. Одна­ко, как ока­залось, задачу мож­но решить и без такой таб­лицы. Леви, к сожале­нию, не при­водит ассем­блер­ный код в сво­ей кни­ге, поэто­му поз­накомить­ся с этим шедев­ром у нас не получит­ся.

Но не спе­ши расс­тра­ивать­ся. Сей­час я покажу тебе свою вер­сию такой под­прог­раммы. Она у меня умес­тилась в 12 инс­трук­ций (и 23 бай­та).

Ко­му‑то может показать­ся, что столь­ко замора­чивать­ся ради того, что­бы сок­ратить раз­мер прог­раммы, в наши дни уже не име­ет смыс­ла. Одна­ко такой навык очень при­гож­дает­ся, ког­да пишешь какой‑нибудь шелл‑код или редак­тиру­ешь ском­пилиро­ван­ный бинар­ник. И в том и в дру­гом слу­чае нуж­но уметь обхо­дить­ся как мож­но мень­шим количес­твом ассем­блер­ных инс­трук­ций. И сей­час я покажу нес­коль­ко трю­ков, которые помогут тебе сок­ращать раз­мер сво­их ассем­блер­ных прог­рамм.

 

Читаем данные из памяти по-новому

Во всех пре­дыду­щих уро­ках мы читали память, ссы­лаясь на нуж­ную нам ячей­ку через регистр BX. При­мер­но вот так.

Но то же самое мож­но сде­лать и вот так.

Инс­трук­ция lodsb говорит про­цес­сору 8088: «Заг­рузи байт из адре­са, на который ука­зыва­ет DS:SI, и сох­рани этот байт в регистр AL. И затем уве­личь SI на еди­ницу (если флаг нап­равле­ния сбро­шен в 0)».

Еще у 8088 есть инс­трук­ция lodsw, которая работа­ет поч­ти как lodsb, толь­ко заг­ружа­ет из DS:SI сло­во (сдво­енный байт), сох­раня­ет резуль­тат в регистр AX и уве­личи­вает SI на 2.

 

Копируем данные, не используя циклы

Зная о сущес­тво­вании инс­трук­ций lodsb/lodsw и их про­тиво­полож­ностей stosb/stows, мы можем написать под­прог­рамму для копиро­вания области памяти.

Этот внут­ренний цикл занима­ет все­го четыре бай­та. Но у про­цес­сора 8088 есть инс­трук­ции movsb и movsw, которые дела­ют ту же самую опе­рацию, но при этом не исполь­зуют регистр AL или AX.

Те­перь внут­ренний цикл занима­ет три бай­та. Но и это не пре­дел! Мы можем сде­лать все то же самое без инс­трук­ции loop.

Об­рати вни­мание, что movsb — это две инс­трук­ции в одной: lodsb и stosb. И ана­логич­но в movsw ском­биниро­ваны lodsw и stosw. При этом movsb/movsw не исполь­зуют регис­тры AL/AX, что весь­ма при­ятно.

Продолжение доступно только участникам

Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте

Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее

Вариант 2. Открой один материал

Заинтересовала статья, но нет возможности стать членом клуба «Xakep.ru»? Тогда этот вариант для тебя! Обрати внимание: этот способ подходит только для статей, опубликованных более двух месяцев назад.


  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    6 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии