Информационная безопасность

       

Архитектура


Для преобразования текста в читабельный вид самыми "горячими" и востребованными будут операции со строками, поскольку и входной и выходной поток - суть последовательность строк. Поэтому вполне естественно, что мы станем использовать Perl - он имеет ни с чем не сравнимые средства для работы со строками и, вместе с тем, является мощным языком высокого уровня, способным справиться и с другими задачами. Поскольку наша программа дизассемблирована под Windows, то будем использовать Windows-версию Perl ActiveState - при желании этот же код потом можно обыграть под Linux.

К архитектуре нашего приложения относится также количество проходов - то есть то, сколько раз наша программа будет сканировать исходный текст. В одно время большим достоинством программы (компилятора в частности) считалась возможность обрабатывать текст за один проход. В результате появились forward-объявления типов и функций, файлы хедеров, дополнительные препроцессоры и т.д. Сегодня, когда цена дисковой и оперативной памяти не является критической, об оптимальном количестве проходов можно спорить. Если программа оперирует одним проходом, она неизбежно хранит много состояний для различных подсистем - и в результате вы, что называется, теряете управление сложностью.

С другой стороны, несколько однопроходных модулей, вызываемых последовательно и соединенных через программные каналы, предоставят ту же производительность при значительно более простом коде. Так мы и сделаем - будем иметь дело с несколькими однопроходными операциями, каждая из которых достаточно проста, чтобы уместиться на одном экране текстового редактора. Поскольку наши "подпрограммы" нужно вызывать в определенном порядке, будем нумеровать файлы подобно тому, как раньше нумеровали строки в qbasic (например, 5,10,20,30 и т.д.),- в случае чего можно вставить в последовательность пару новых элементов, и при этом будет ясно, что за чем идет.

Командный файл для запуска будет примерно таким:

perl -n 1.pl СБ.asm | perl -n 2.pl | perl -n 3.pl 1>СБ.out


Ключ - n не просто экономит несколько строк кода - он буквально принуждает нашу программу работать определенным образом, то есть получать на входе в переменной $_ одну за одной строки asm-файла и также по одной их обрабатывать. Конечно, никто не запрещает хранить строки во внутреннем хранилище, например в массиве. После обработки каждый блок должен возвращать все строки в исходном или модифицированном виде в выходной поток для дальнейшей обработки. Тривиальный модуль, как минимум, должен вернуть все строки без обработки:

print;

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

Такое поведение, вообще говоря, позволяет делать более сложные вещи, но мы хотим поддерживать код настолько простым, насколько это возможно. В идеале порядок проходов совершенно не должен иметь значения, но неявно мы все время будем использовать зависимости - поскольку от перестановки проходов производительность будет меняться в диапазоне от "отлично" до "неприемлемо". Например, после замены всех "white spaces" на единичные пробелы мы можем везде вместо "\s+" использовать " ", что значительно проще для regexp-движка, и так далее.


Содержание раздела