Воробьёвы

(-:

№9. Из интимной жизни программера: HEX в BIN... и разборки с процедурами

БЛАЖЕННЫ НЕ ИМЕЮЩИЕ ИНЕТА, ИБО ИХ ЕСТЬ ЦАРСТВИЕ НЕБЕСНОЕ

Дело было так: посмотрел сисадмин на траффик, "генерируемый" нашим "почтовым роботом", и сказал: "Я убью тебя, Serrgio"!

Само собой, ДZенский напиток в очередной раз спас мою драгоценную жизнь, но спасти жизнь почтового робота-убийцы оказалось не под силу даже ему. А на живую огненную воду денег на тот момент не было...

Так вот: самая большая беда заключается в том, что пока я бегал в поисках "капусты", на сисадмина наехал шеф, вследствие чего наш сисадмин впал в неблагоприятное для решения подобных вопросов состояние духа... И сколько мы с ним не дZенствовали, мне так и не удалось убедить его не обижать наших блаженных Инетом подписчиков :((.

И знаете, что он сделал?? Убить - не убил, но придушил, надо сказать, основательно...

Итог этих всех неприятных событий таков: "робот" теперь будет рассылать не более 50 "ответных писем" в сутки. Те, у кого действительно нет Интернета - они-то рано или поздно дождутся предыдущих номеров. А вот те, у кого Интернет есть, но они все равно захотели "нахаляву" - таким ПОЗОР и мое личное дZенское презрение...

ПРЕДЫДУЩИЕ ВЫПУСКИ РАССЫЛКИ

Ну не то, чтобы повторение - мать учения... просто не проштудировав материал прыдыдущих номеров, вам будет весьма затруднительно "въехать" в номер текущий...

Выпуск 2 - про систему счисления.

Выпуск 3 - про порядок загрузки компьютера.

Выпуск 4 - про регистры.

Выпуск 5 - про программу в памяти.

Выпуск 6 - про прерывания.

Выпуск 7 - программируем и отлаживаем.

Выпуск 8 - "ломаем" игры, разборки со стеком, циклами, оптимизацией...

Кстати, у кого проблемы с интернетом... хм... это только ваши проблемы и к нам по этому поводу обращаться не стоит...

ВДОГОНКУ К НОМЕРУ 8 ВМЕСТЕ С ГНИЛЫМИ ПОМИДОРАМИ

После 8-го выпуска рассылки в адрес "редакции" пришел ряд гневных писем. Типа мы тут народ взлому программного обеспечения учим. Это надо же!! Игры мы тут, понимаете ли, "кракаем" :((. Противозаконно это, видите-ли :((.

Чушь!! Притом полная!! Противозаконным является всяческое копание в бинарнике с целью, например, обхода той или иной защиты от копирования. А то, что мы "делаем с играми" - с точки зрения текущего законодательства всех развитых, неразвитых и недоразвитых стран вполне безобидно. Так что даже и не делайте попытку на нас из-за этого наезжать...

ЗЛОБНАЯ МИНИАТЮРКА ДЛЯ РАZОГРЕВУ

Тут некоторым начинающим программерам CD 18 по неопытности понравилось :). Так вот, дрожащими руками ловите еще одну симпатичную миниатюрку (сразу предупреждаю, что программулька очень нехорошая):

     :0100 CLI
     :0101 JMP 0100 

А почему ей INT 20h не нужен - вы и сами догадаетесь, когда запустить попробуете...

На WINDOWS-2000, кстати, она работает не совсем корректно ;)

ИЗ ИНТИМНОЙ ЖИЗНИ ПРОГРАММЕРА: HEX В BIN

Некто Алексей в гостевой книге рассказал, как на вшивость своих коллег (мега-пупер-программеров) проверял. Вопрос простой был: перевести число из HEX'а в BIN. И что же? Имея высшее-компьютерное образование, они не смогли это сделать. Не то что в уме - даже "на листике" это у них заняло весьма длительное время. Да и ответ в конце-концов был неправильный...

Все почему-то переводили сначала их HEXа в DEC, а потом из DECа в BIN :(. А над вопросом, зачем вообще этот HEX нужен, никто и никогда, наверное, не задумывался...

А стоило бы!!

Всех, у кого подобные проблемы, отсылаю к выпуску #2 , особенно к п. 12.

И не стоит забывать прописную истину, которой нас учили еще в средней школе - ПОВТОРЕНИЕ - МАТЬ УЧЕНИЯ! (Верите?)

ПРОВЕРЬТЕ! ОН МОЮ СЕСТРУ ОБМАНУЛ...

А еще мега-пупер-ассемблерщики наезжали. Типа лапшу мы "читателям" вешаем :). Прежде чем объяснять "политику партии" (все ж обидно, когда коллеги критикуют), мы им один простой вопрос "на крутость" задавали:

Сколько раз выполнится следующий цикл:

  :0102 MOV CX,0000 
  :0105 ADD AX,0001 
  :0108 LOOP 0105 

Очевидный ответ - 0 раз. В CX же 0 у нас занесен. Так вот: ответ неправильный.

Менее очевидный ответ - 1 раз! Ведь перед LOOP'ом сложение один раз выполнится-таки... Так вот: этот ответ тоже неправильный.

Самые подозрительные могут сразу же посмотреть на этот цикл под отладчиком и с удивлением обнаружат, что LOOP сначала уменьшает значение CX (0-1=FFFF), а потом уже проверяет, не равен ли он нулю... И с гордостью за задний ум своей головы воскликнут: FFFFh раз!!

Так вот: этот ответ близок к истине, но тоже неправильный ;)

Правильный ответ - цикл выполнится 10000h (65536d) раз.

Это тем более прикольно, что в некоторых умных книжках черным по белому сказано, что, "увы, максимум мы можем выполнить цикл FFFFh раз"...

Но только вы и мне не верьте! Истинно только то утверждение, которое вы сами проверили на практике...

О чем это я?? Ах да!! О "критиках"... да, в общем-то, черт с ними, с этими "критиками"... Пускай ругают, сколько хотят! У них свой путь, а у нас - свой... И если им с нами не по пути - то это только их проблемы.

Наша же дорога трудна. В ней нет "порталов", которые помогают пересекать огромные расстояния "нахаляву", нет хорошей заасфальтрованной дороги... Есть только многочисленные указатели, один из которых посылает налево, другой направо, а третий вообще на три веселых буквы...

А дорога такая: 86, 286, 386, 486, p, p2. С "привалами" на MMX, 3DFX и прочей "дури". Соответственно и "платформы" - сначала DOS и только потом WIN и WIN32. Оговорюсь сразу: к "звездам" - исключительно через "тернии". Правда, с многочисленными "тоже звездами" - но это от систематических ударов по голове...

Сказано же черным по белому на сайте "старшего брата": "Рассылка "Низкоуровневое программирование для дZeнствующих" целиком посвящена программированию на ассемблере, начиная с самых фундаментальных его основ"!

Вот мы вам и пытаемся дать ЭТО - фундаментальные основы. Ну а зачем они нужны, вы и сами знаете - чтоб крыша не поехала, чуть ветер дунет...

А ветер - скоро дунет!! Спросите у линуксоидов...

СЛЕДУЙ ЗА БЕЛЫМ КРОЛИКОМ!

РАЗБОРКИ С ПРОЦЕДУРАМИ

[1] В #7 (п. 4.) мы сделали глупую линейную программульку, выводящую окошки. Обещал я было, что в следущем выпуске мы ее сделаем менее "тупой", да отвлекся на циклы и стек почему-то... То есть я-то знаю, ПОЧЕМУ, но вот вам об этом - не скажу! Догадайтесь сами...

Итак, поехали...

Шаг первый. Внимательно посмотрев на "линейную" прогу из седьмого номера и прочитав "условие задачи" из п.1 вы обязаны возмутиться: зачем мы использовали команду MOV, если и ежу понятно, что отличия последующего окошка от предыдущего можно выразить более лаконично: BH=BH+10, CH=CH+1, CL=CL+1, DH=DH-1, DL=DL-1 ? И не нужно напрягать мозги, подсчитывая новое значение регистра вручную...

Если вы так подумали, то оказались совершенно правы!!

Программу из #7 запросто можно было представить в таком вот виде:

     
     :0100 XOR AL,AL     ;окошко первое 
     :0102 MOV BH,10 
     :0104 MOV CH,05 
     :0106 MOV CL,10 
     :0108 MOV DH,10 
     :010A MOV DL,3E 
     :010C MOV AH,06 
     :010E INT 10 
     :0110 ADD BH,10     ;окошко второе 
     :0113 ADD CH,01 
     :0116 ADD CL,01 
     :0119 SUB DH,01 
     :011C SUB DL,01 
     :011F INT 10 
     :0121 ADD BH,10     ;окошко третее 
     :0124 ADD CH,01 
     :0127 ADD CL,01 
     :012A SUB DH,01 
     :012D SUB DL,01 
     :0130 INT 10 
     :0132 ADD BH,10     ;окошко четвертое 
     :0135 ADD CH,01 
     :0138 ADD CL,01 
     :013B SUB DH,01 
     :013E SUB DL,01 
     :0141 INT 10 
     :0143 ADD BH,10     ;окошко пятое 
     :0146 ADD CH,01 
     :0149 ADD CL,01 
     :014C SUB DH,01 
     :014F SUB DL,01 
     :0152 INT 10 
     :0154 INT 20        ;конец программы 

И несмотря на то, что размер ее оказался несколько большим, она тоже будет работать правильно :)

Но тут любой более-менее наблюдательный программер возмутится повторно: да что это за программа такая?? В ней целых 4 раза повторяется один и тот же кусок:

     :0143 ADD BH,10
     :0146 ADD CH,01 
     :0149 ADD CL,01 
     :014C SUB DH,01 
     :014F SUB DL,01 
     :0152 INT 10

И знаете что?? Этот наблюдательный программер будет прав! А если он еще и выразится матом по поводу такого "неправильного" стиля программирование - то он будет прав АБСОЛЮТНО!

Внимательно всмотритесь в полный текст программы и в этот выделенный кусок... И помедитируйте над ним до полного просветления текущей "обстановки"...

[2] Итак, у нас есть ПОВТОРЯЮЩАЯСЯ ЧАСТЬ программы. А еще у нас есть пальцы, которым, как правило, лень набивать длинные "простыни" программного кода. Это одна из многочисленных причин, по которым и придумали такого зверя, как ПРОЦЕДУРУ (она же - ПОДПРОГРАММА). Остальные причины, мы рассмотрим попозже, а вот на счет "лени" поговорим прямо сейчас:

Если мы возмем наш частоповторяющийся кусок программы и допишем в ее конец команду RET, то получится у нас именно ПРОЦЕДУРА - во всей своей красе...

 
     :011E ADD BH,10    ;"точка входа"; она же - начало "тела".
     :0121 ADD CH,01 
     :0124 ADD CL,01 
     :0127 SUB DH,01 
     :012A SUB DL,01 
     :012D INT 10       ;конец "тела" 
     :012F RET 

Красота ее вот в чем заключается: процедуру можно "вызвать" командой CALL :)))

Все более чем просто :). Когда в программе встречается CALL с указанием АДРЕСА-НАЧАЛА-ПРОЦЕДУРЫ (в нашем случае это 011E), то "компьютер" "идет" по этому адресу и выполняет все команды, ресположенные между "точкой входа" (включительно) и командой RET, то есть так называемое "тело" процедуры.

RET - это тоже команда, но к "телу" (адреса 11E... 12D) она не относится. Она является "ОРГАНИЗАТОРОМ" этого "тела". Процессор, встретив команду RET, "перепрыгивает" на строчку ниже "вызвавшего" данную процедуру CALL'а...

Короче: CALL XXXX - означает "выполнить процедуру, начинающуюся по адресу XXXX". А RET - означет "конец процедуры" и, соответственно, переход на строчку ниже вызвавшего его CALL'а.

Не ругайтесь. Я знаю, что вы ничерта не поняли. А по сему набьем в debug'е эту прогу и посмотрим, что она делает...

[3] Кстати, вы уже поняли, почему я называю debug "до боли любимой программой"? Нет?? Неужели вы еще не полюбили это произведение программерского гения всеми фибрами своей души?

Еще нет??

М-да... я вас разочаровался... А по сему:

"НАБИВАЕМ!" - злобно кричу я вам, брызгая слюной на свой эргономичный коврик...

    :0100 XOR AL,AL    ;первое окошко рисуем, как и раньше...
    :0102 MOV BH,10 
    :0104 MOV CH,05 
    :0106 MOV CL,10 
    :0108 MOV DH,10 
    :010A MOV DL,3E 
    :010C MOV AH,06 
    :010E INT 10 
    :0110 CALL 011E    ;четыре раза вызываем подпрограмму, начинающуюся
    :0113 CALL 011E    ;по адресу 011E
    :0116 CALL 011E 
    :0119 CALL 011E 
    :011C INT 20       ;выход из программы...
    :011E ADD BH,10    ;начало процедуры
    :0121 ADD CH,01 
    :0124 ADD CL,01 
    :0127 SUB DH,01 
    :012A SUB DL,01 
    :012D INT 10 
    :012F RET          ;конец процедуры 

Не правда ли, красиво получилось??

А то!

Первое, что вас может смутить, это то, что команда выхода (INT 20) расположена не там, где вы привыкли, то есть не в конце программы.

Ну что я вам могу на это ответить? Концы-то - они разные бывают! Последняя строчка в листинге вовсе не означает, что последней будет выполняться именно она. И это не должно вас смущать!! А если все-же смущает - смотрим, как работает эта прога из-под отладчика...

Итак, до адреса 0110 вам все должно быть понятно. Мы это рассматривали. Трассируем дальше...

Команда CALL 011E по адресу 0110 говорит поцессору: "дальше мы не пойдем, пока не выполним простыню, начинающуюся по адресу 011E"; и далее, естественно, следует переход на этот адрес.

Входим в тело процедуры, начиная с 011E и выполняем команды до 012D включительно...

А теперь внимательно смотрим, на какой адрес нас "перекинет" команда RET.

На 113-й? И это правильно!

По 113-му адресу у нас какая команда? Да вот опять CALL 011E!

Опять процедура с адреса 011E, опять RET[URN] на строку ниже, то есть на 116...

И так далее до того момента, пока следующей строчкой не окажется INT 20 - собственно, на этом и программе конец.

Ну оно и ежу понятно, что несмотря на то, что INT 20 - не в конце программы, последним выполнится именно он.

Короче, куда бы вас не посылали всяческие "столбы с указателями", конец вашего пути только один - ГРОБ. А плутать вокруг да около этого гроба вы можете сколько вам заблагорассудится...

Кстати, именно это и является одной из многочисленных тайн структурного программинга...

Кто после этого скажет, что программисты - не дZенствующие люди??

[4] Те, кто читал прошлый номер, они и на этом не остановятся!! Посмотрев на адреса 110...119, они вообще возьмут и возомнят себя воистину крутыми парнями!

Знаете, что они напишут??

А вот что (предвижу!):

    :0100 XOR AL,AL 
    :0102 MOV BH,10 
    :0104 MOV CH,05 
    :0106 MOV CL,10 
    :0108 MOV DH,10 
    :010A MOV DL,3E 
    :010C MOV AH,06 
    :010E INT 10 
    :0110 MOV CX,0004 
    :0113 CALL 011A 
    :0116 LOOP 0113 
    :0118 INT 20 
    :011A ADD BH,10 
    :011D ADD CH,01 
    :0120 ADD CL,01 
    :0123 SUB DH,01 
    :0126 SUB DL,01 
    :0129 INT 10 
    :012B RET 

То бишь еще и CALL в цикл при помощи MOV CX,4 и LOOP'а "закрутят". И что? А попробуйте!

Что, не "пашет"? А что надо делать, если "не пашет, а должно бы"? Правильно! Смотреть из-под отладчика!

Смотрим? Если посмотрите, то сразу же и "загвоздку" увидите! CX, использованный в качестве "счетчика" циклов, "перебивает" тот же CX, но используемый как "координаты верхнего левого угла окна". И что с этим делать прикажете??

Вот... вы столкнулись с одной из самых больших проблем. В компьютере есть только 4 переменные, помните я вам говорил об этом?

И теперь догадайтесь, как выкрутиться из этой нехорошей ситуации с использованием стека??

В общем, вот что: медитируйте-ка вы до следующей недели, а там посмотрим :)

АНОНС!

Это Нового года может не быть! Следующий номер рассылки - будет! Даже если мне на голову еще один кирпич свалится... - следующий номер все равно будет!!

Может по-приколу с наступающим новым тысячелетием всех поздравить?

Не хочу и не буду!

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

ДА НЕ НАКАРКАЕТ НАМ БИЛЛГЕЙТС БЕДЫ СВОИМ WINDOWS-MILLENIUM'ом!

Крепите дух, братья! Нас ждут страшные годы...