ЛЕГЕНДА О ХАКЕРЕ. МЭЛ КЕЙ
<Usenet> автор: Эдд Нейзер.
Утро. 21 мая 1983 год.
Транслятор: Bereg
В недавней статье, посвященной «мачизму» в программировании, было сделано откровенное заявление: «Настоящие программисты пишут на Фортране».
Может быть, сейчас, в эту декадентскую эпоху светлого пива, ручных калькуляторов и «дружественного к пользователю» программного обеспечения, так оно и есть, но в старые добрые времена, когда термин «программное обеспечение» звучал забавно, а настоящие компьютеры делались из барабанов и электронных ламп, настоящие программисты писали на машинном коде — не на Фортране, не на RATFOR, даже не на языке ассемблера, а на машинном коде, — на чистом, не приукрашенном, непостижимом шестнадцатеричном коде...
Чтобы целое поколение программистов не выросло в неведении об этом славном прошлом, я считаю своим долгом как можно подробнее, несмотря на разницу поколений, рассказать о том, как настоящий программист писал код. Я назову его Мэл, потому что так его звали.
Я впервые встретился с Мелом, когда устроился на работу в Royal McBee Computer Corporation, ныне несуществующую дочернюю компанию производителя пишущих машинок. Фирма выпускала LGP-30, небольшой и дешевый (по меркам того времени) компьютер с барабанной памятью, и только начала производить RPC-4000 — значительно улучшенный, более крупный, совершенный и быстрый компьютер с барабанной памятью. Ядра стоили слишком дорого, да и в любом случае это было временное решение. (Вот почему вы не слышали ни о компании, ни о компьютере.)
Меня наняли для написания компилятора Fortran для этого нового чуда техники, и Мэл был моим проводником в мир его чудес. Мэл не одобрял компиляторы.
«Если программа не может переписать свой собственный код, — спрашивал он, — какой от нее толк?».
Мэл написал в шестнадцатеричной системе счисления самую популярную компьютерную программу в компании. Он работал на LGP-30 и играл в блэкджек с потенциальными клиентами на компьютерных выставках. Эффект всегда был потрясающим. Стенд LGP-30 был забит посетителями на каждой выставке, а продавцы IBM стояли вокруг и разговаривали друг с другом. Вопрос о том, действительно ли это помогало продавать компьютеры, мы никогда не обсуждали.
Задача Мела заключалась в том, чтобы переписать программу для блэкджека для RPC-4000. (Порт? Что это значит?) В новом компьютере использовалась схема адресации «один плюс один», при которой каждая машинная инструкция, помимо кода операции и адреса необходимого операнда, содержала второй адрес, указывающий, где на вращающемся барабане находится следующая инструкция. Говоря современным языком, за каждой инструкцией следовала команда перехода! Засуньте *это* в трубку Паскаля и выкурите.
Мэл любил RPC-4000 за то, что с его помощью можно было оптимизировать код: то есть расположить инструкции на барабане так, чтобы, как только одна из них завершала свою работу, следующая уже подходила к «головке чтения» и была готова к немедленному выполнению. Для этого существовала программа — «оптимизирующий ассемблер», но Мэл отказывался ею пользоваться.
«Никогда не знаешь, куда он что поместит, — объяснил он, — поэтому приходится использовать отдельные константы». Мэл
Прошло много времени, прежде чем я понял это замечание. Поскольку Мел знал числовое значение каждого кода операции и назначал свои собственные адреса барабанов, каждую написанную им инструкцию также можно было считать числовой константой. Он мог взять более раннюю инструкцию "добавить", скажем, и умножить на нее, если у нее было правильное числовое значение. Его код было нелегко модифицировать кому-либо другому.
Я сравнил программы Мэла, оптимизированные вручную, с тем же кодом, обработанным оптимизирующей программой на ассемблере, и у Мэла всегда получалось быстрее. Это произошло потому, что метод разработки программ "сверху вниз" еще не был изобретен, и Мел все равно бы им не воспользовался. Сначала он написал самые внутренние части циклов своей программы, чтобы они могли первыми выбирать оптимальные расположения адресов на барабане. Оптимизирующий ассемблер был недостаточно умен, чтобы сделать это таким образом.
Мэл также никогда не писал циклы с временной задержкой, даже когда неуклюжему Flexowriter требовалась задержка между выводимыми символами для правильной работы. Он просто расположил инструкции на барабане так, чтобы каждая последующая находилась *сразу за* считывающей головкой, когда она была нужна; барабану приходилось совершать еще один полный оборот, чтобы найти следующую инструкцию. Он придумал для этой процедуры незабываемый термин. Хотя слово «оптимальный» является абсолютным, как и слово «уникальный», в разговорной речи его стали использовать в относительном смысле: «не совсем оптимальный», «менее оптимальный» или «не очень оптимальный». Мэл назвал места с максимальной задержкой «самыми пессимистичными».
После того как он закончил работу над программой для блэкджека и запустил ее («Даже инициализатор оптимизирован», — с гордостью сказал он), он получил запрос на внесение изменений от отдела продаж. Программа использовала элегантный (оптимизированный) генератор случайных чисел для перетасовки «карт» и раздачи из «колоды», и некоторые продавцы считали, что она слишком честная, поскольку иногда клиенты проигрывали. Они хотели, чтобы Мэл модифицировал программу таким образом, чтобы при нажатии сенсорной кнопки на консоли можно было изменить коэффициенты и позволить клиенту выиграть.
Мэл воспротивился. Он считал, что это откровенная нечестность, и это действительно было так, и что это подрывает его личную честность как программиста, и это действительно было так, поэтому он отказался это делать. С Мэлом поговорил главный менеджер по продажам, а также Большой Босс и, по настоянию босса, несколько коллег-программистов. В конце концов Мэл сдался и написал код, но он сделал тест наоборот, и, когда включался переключатель, программа жульничала и каждый раз выигрывала. Мэл был в восторге от этого, утверждая, что его подсознание не поддается контролю, и категорически отказывался что-либо исправлять.
После того как Мэл ушел из компании в поисках лучшей жизни, Большой Босс попросил меня взглянуть на код и попытаться найти тест и обратить его. Я нехотя согласился. Поиск кода Мэла оказался настоящим приключением...
Я часто думал о том, что программирование — это вид искусства, истинную ценность которого может оценить только тот, кто сведущ в этом тайном искусстве.
Есть прекрасные жемчужины и блестящие находки, которые скрыты от человеческого взгляда и восхищения, иногда навсегда, самой природой процесса. Можно многое узнать о человеке, просто прочитав его код, даже в шестнадцатеричном формате. Мел, на мой взгляд, был невоспетым гением.
Пожалуй, больше всего я был потрясен, когда обнаружил безобидный цикл без проверки. Без проверки. *Без проверки*. Здравый смысл подсказывал, что это должен быть замкнутый цикл, в котором программа будет ходить по кругу вечно, бесконечно. Однако управление программой проходило прямо через него и благополучно выходило с другой стороны. Мне потребовалось две недели, чтобы это понять.
В компьютере RPC-4000 была очень современная функция — индексный регистр. Это позволяло программисту написать цикл программы, в котором использовалась индексированная инструкция: при каждом проходе число в индексном регистре прибавлялось к адресу этой инструкции, чтобы она ссылалась на следующий элемент в последовательности. Программисту нужно было лишь увеличивать индексный регистр при каждом проходе. Мел никогда этим не пользовался.
Вместо этого он переносил инструкцию в машинный регистр, прибавлял единицу к ее адресу и сохранял обратно. Затем он выполнял измененную инструкцию прямо из регистра. Цикл был написан таким образом, чтобы учитывать это дополнительное время выполнения: как только эта инструкция заканчивалась, следующая оказывалась прямо под считывающей головкой барабана и была готова к выполнению. Но в цикле не было проверки.
Ключевая догадка пришла ко мне, когда я заметил, что бит индексного регистра, расположенный между адресом и кодом операции в слове инструкции, был включен, хотя Мэл никогда не использовал индексный регистр, оставляя его всегда нулевым. Когда меня осенило, я чуть не ослеп от радости.
Он расположил данные, с которыми работал, в верхней части памяти — в самых больших ячейках, на которые могли ссылаться инструкции, — поэтому после обработки последнего элемента данных увеличение адреса инструкции привело бы к переполнению. Перенос прибавлял единицу к коду операции, изменяя его на следующий в наборе команд: команду перехода. Разумеется, следующая программная команда находилась по нулевому адресу, и программа благополучно продолжала работу.
Я давно не общался с Мелом, поэтому не знаю, поддался ли он потоку изменений, захлестнувшему методы программирования с тех давних времен. Мне хочется думать, что нет. В любом случае я был настолько впечатлен, что перестал искать проблемный тест и сказал Большому Боссу, что не смог его найти. Он не удивился.
Когда я уходил из компании, программа для игры в блэкджек по-прежнему жульничала, если вы включали правильный переключатель sense, и я думаю, что так и должно быть. Я не чувствовал себя комфортно, взламывая код настоящего программиста...






