Седякин.md 21 KB

Компилятор и декомпилятор

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

Виды компиляторов:

  • Векторизующий. Компилирует исходный код в машинный код для компьютеров, оснащённых векторным процессором.
  • Гибкий. Сконструирован по модульному принципу, управляется таблицами и запрограммирован на языке высокого уровня или - реализован с помощью компилятора компиляторов.
  • Инкрементальный. Повторно транслирует/компонует фрагменты программы и дополнения к ней без перекомпиляции всей программы.
  • Интерпретирующий (пошаговый). Последовательно выполняет независимую компиляцию каждого отдельного оператора (команды) исходной программы.
  • Компилятор компиляторов. Компилятор, воспринимающий формальное описание языка программирования и генерирующий компилятор для этого языка.
  • Отладочный. Устраняет отдельные виды синтаксических ошибок.
  • Резидентный. Постоянно находится в оперативной памяти и доступен для повторного использования многими задачами.
  • Самокомпилируемый. Написан на том же языке, с которого осуществляется компиляция.
  • Универсальный. Основан на формальном описании синтаксиса и семантики входного языка. Важными составными частями такого компилятора являются: ядро, синтаксический и семантический загрузчики.

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

Виды компиляции:

  • Пакетная. Компиляция нескольких исходных модулей в одном задании.
  • Построчная. Машинный код порождается и затем исполняется для каждой завершённой грамматической конструкции языка. Внешне воспринимается как интерпретация, но имеет иное устройство.
  • Условная. На фазе трансляции результат трансляции зависит от условий, прописанных в исходном транслируемом тексте программы директивами компилятора.

История создания

Создание первых программ компиляции следует отнести к началу пятидесятых годов прошлого века. Главной задачей реализации первых компиляторов в то время было решение проблемы преобразования алгебраических выражений в машинные коды. А фактическим годом рождения теории компиляции может считаться 1957-ой год, когда была реализована первая программа компиляции языка Фортран, сформированная Джоном Бэкусом и выдававшая довольно эффективные объектные (машинные) коды. Этот компилятор был предназначен для платформ IBM 704, IBM 360 и DEC PDP-11. В восьмидесятом году прошлого века вышел новый вариант компилятора, предназначенный для IBM 360 и IBM РС, который поддерживал стандарт Fortran 77. Годом позже образовалась компания Watcom, представившая в 1988-ом году программу компиляции Си. Она мгновенно стала чрезвычайно популярной среди специалистов по программированию, поскольку могла генерировать наиболее быстрые коды в сравнении с другими компиляторами тех времён.

Джон Бэкус

Джон Бэкус

Принцип работы

Компилятор – это системная программа, которая воспринимает на входе текст программы на языке высокого уровня (исходный модуль), а на выходе генерирует программу на языке ассемблера или машинном языке (объектный модуль). Объектный модуль состоит из двух основных частей: тела модуля, представляющего собой программу в кодах команд конкретной ЭВМ, и заголовка, содержащего внешние имена (имена переменных, используемых в данном модуле, но определённых в других модулях). Эта информация необходима для построения из набора объектных модулей программы или программной системы,готовой к выполнению. Объектные модули обрабатываются компоновщиком (редактором связей), который строит исполняемую программу (исполняемый файл, exe-модуль, загрузочный модуль) содержащую только команды ЭВМ.

Компилятор

Принцип работы компилятора

Компиляция работает быстрее интерпретации, потому что компилятор запускается только один раз: делает перевод и отдает его процессору. Интерпретатор же запускается на каждой строке кода и нужен при каждом запуске программы. Кроме того, программный код в компиляторе уже переведен в машинный, поэтому требуется намного меньше времени для его исполнения. Поэтому, при разработке объёмных приложений лучше использовать компилятор. В то время как интерпретатор будет превосходить по скорости компилятор при использовании его в разработке небольших приложений.

Отдельные программы компиляции, к примеру, Java, способны переводить программу не в машинные коды, а в программу на определённом специализированном языке низкого уровня. Данный язык, или по-другому байт-код, тоже может считаться языком машинных кодов, так как он должен интерпретироваться виртуальной машиной. К примеру, для языка Java языком виртуальной машины является JVM, или иначе байт-код Java.

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

Помимо этого, программы компиляции можно оптимизировать для разных типов процессоров из единого семейства. К примеру, коды, сформированные компилятором для процессоров семейства i686, могут применять специфические для данных процессоров инструкции ММХ, SSE, SSE2. Имеются также программы, решающие обратную задачу, а именно, они переводят программы с языка низкого уровня на язык высокого уровня. Такая процедура именуется декомпиляцией, а выполняющие её программы называются декомпиляторами.

Структура компилятора

Любой компилятор состоит из транслятора и компоновщика. Часто в качестве компоновщика компилятор использует внешний компоновщик, реализованный в виде самостоятельной программы, а сам выполняет лишь трансляцию исходного текста (по этой причине многие ошибочно считают компилятором разновидность транслятора). Компилятор может быть реализован и как своеобразная программа-менеджер, для трансляции программы вызывающая сооствествующий транслятор (трансляторы - если разные части программы написаны на разных языках программирования) и затем - для компоновки программы, - вызывающая компоновщик. Ярким примером такого компилятора является имеющаяся во всех UNIX-системах (и Linux-системах в том числе) утилита make (имеются реализации утилиты make и в других системах, в частности в Windows-системах).

Процесс компиляции состоит из следующих фаз:

  1. Лексический анализ. На этой фазе последовательность символов исходного файла преобразуется в последовательность лексем.
  2. Синтаксический (грамматический) анализ. Последовательность лексем преобразуется в древо разбора.
  3. Семантический анализ. Древо разбора обрабатывается с целью установления его семантики (смысла) — например, привязка идентификаторов к их определениям, типам данных, проверка совместимости типов данных, определение результирующих типов данных выражений и т. д. Результат обычно называется «промежуточным представлением/кодом», и может быть дополненным древом разбора, новым древом, абстрактным набором команд или чем-то ещё, удобным для дальнейшей обработки.
  4. Оптимизация. Удаляются избыточные команды и упрощается (где это возможно) код с сохранением его смысла, т. е. реализуемого им алгоритма (в том числе предвычисляются (т. е. вычисляются на фазе трансляции) выражения, результаты которых практически являются константами). Оптимизация может быть на разных уровнях и этапах — например, над промежуточным кодом или над конечным машинным кодом.
  5. Генерация кода. Из промежуточного представления порождается код на целевом языке (в том числе выполняется компоновка программы).

Примеры компиляторов

Для Windows:

  • Borland C++ Compiler
  • C++Builder XE7
  • Dev-C++
  • Microsoft Visual C++

Для Unix:

  • g++
  • GNU Compiler Collection
  • Oracle Solaris Studio

Достоинства и недостатки

Достоинства компилятора:

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

Недостатки компиляторов:

  • Использует гораздо больше памяти компьютера.
  • При работе с компилятором невозможно изменить программу, не вернувшись к исходному коду.
  • Необходимо создавать объектную программу перед окончательным исполняемым файлом. Это может занять много времени.
  • Исходный код должен быть на 100% верным для создания исполняемого файла.

Декомпиляция

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

Декомпилятор - это программа, транслирующая исполняемый модуль (полученный на выходе компилятора) в эквивалентный исходный код на языке программирования высокого уровня.

Декомпиляция - процесс воссоздания исходного кода декомпилятором.

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

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

Если известно на каком языке была написана декомпилируемая программа, то в первую очередь дизассемблируются и анализируются библиотеки времени исполнения (RTL — runtime library) компилятора с этого языка, так как в основном компиляция программы сводится к вызовам с различными параметрами процедур из этих библиотек. Кроме того, многие компиляторы позволяют увидеть, в какой ассемблерный код превращаются операторы программы после компиляции. Эти конструкции становятся шаблонами для декомпилятора, поэтому процесс декомпиляции в некотором смысле похож на распознавание в машинном коде конечного набора подобных шаблонов. Легче всего распознаются вызовы процедур и возвраты из них. Они служат границами для восстановления операторов процедуры.

Примеры декомпиляторов:

  • FernFlower
  • .NET Reflector, dotPeek — для декомпиляции сборок .NET
  • ILSpy
  • Delphi Decompiler
  • JAD — JAva Decompiler

Для чего нужен декомпилятор:

  • взлом коммерческих программ и видеоигр.
  • исследование работы программы (реверс-инжиниринг). Например, есть мессенджер Skype. Протокол его взаимодействия с сервером не опубликован. А мы хотим создать свой мессенджер, который может работать в сети Skype. Или хотим сделать чит к игре.
  • поиск уязвимостей в программе, исходный код которой недоступен.
  • чтобы видеть не только ЧТО программа делает, но и КАК она это делает.

Таким образом, мы познакомились с такими понятиями, как: компилятор, компиляция, декомпилятор, декомпиляция. Узнали как работает компилятор и для чего нужен декомпилятор.

Список литературы

Декомпилятор

Компилятор

Компилятор против интерпертатора. Ключевые отличия

Компиляторы: история создания и развития

Компиляция и интерпретация кода: что это такое и в чём разница

Принципы работы компилятора

Структура компиляторов. Общая схема работы компилятора