Аркод: генерация и выполнение

В предыдущей заметке я писал о том, что текущую Тривиль генерацию нельзя использовать, как есть для Аркода.

Напомню, что говоря «архитектурное программирование», мы держим в уме:

  • сборку исполняемой программы (или части, которая работает на устройстве) из компонент. Сборка должна быть и статической и динамической, более того, переход между статической и динамической сборкой должен быть бесшовным.
  • мультиплатформенность (иначе нет смысла)

Из этого следует, что использовать объектные файлы и динамические библиотеки, например, COFF/dll и Elf/so, по меньшей мере, неудобно. А скорее и невозможно в том смысле, что недостатков в таком подходе больше, чем достоинств.

Собственно, до 2006 года я пытался построить Вир (сборочное программирование) на dll. В 2006 году я отказался, перешел на свой компилятор Вир/а0 и свой формат объектного и исполняемого (он же загружаемого) файла. Каждый инструмент компилировался в объектный файл, а далее статический линкер собирал из него исполняемый файл. Решение оказалось простым и гибким, и позволило быстро продвинутся дальше. Для того, чтобы использовать внешний софт, можно было подключить DLL.

Основной недостаток такого решения — не переносимость. Генерация в Вир/а0 была только на x86. Второй недостаток — производительность, код генерился предельно просто, никаких оптимизаций не делалось. Скорость работы программ достигалась за счет архитектуры.

При разработке Вир/а1 переносимость меня уже волновала. Компилятор Вир/а1 порождал LLVM IR. А дальше проделывался следующий фокус:

  • с помощью утилиты llc строился объектный файл (в формате COFF),
  • потом из него извлекался сегмент кода и таблица связей
  • и записывался объектный файл в формате Вир/а0
  • а дальше так же, как для Вир/а0

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

Итак, я могу сформулировать задачу так: компилятор должен строить объектный файл в одном и том же (своем) формате для разных платформ и этот формат должен быть удобен для статической и динамической линковки.

Какие есть варианты:

  1. Вариант Вир/а0: своя генерация кода для каждой платформы
  2. Вариант Вир/а1: генерация кода с помощью имеющихся инструментов (например, clang) и переупаковка (платформенно-зависимая) в единый формат.
  3. Вариант Java: Генерация кода для виртуальной машины, объектный код для ВМ. Подварианты: 1) взять готовую VM или 2) написать свою.

Вариант 1:

  • За: полностью свое решение
  • Против: Трудоемко, долго. Много работы для каждой платформы. Не имеет смысл конкурировать с LLVM, по крайней мере, прямо сейчас.

Вариант 2:

  • За: Умеренная трудоемкость, производительность решения
  • Против: Отдельная работа для каждого формата объектного файла, а может быть и для платформы, если есть особенности.

Вариант 3.1:

  • За: переносимость
  • Против: Придется выбирать и вписываться в готовую VM. Там все будет трещать по швам и плохо сшиваться. А это трудоемко и придется много ругаться.

Вариант 3.2:

  • За: переносимость
  • Против: Много работы, которая напрямую не связана с архитектурным программирование — слишком окольный путь. Производительность существенно проигрывает всем остальным вариантам.

Итого: На мой взгляд, вариант 2. При этом переход на LLVM IR не имеет смысла, можно генерить Си, только учитывать особенности генерации, получать объектный файл и далее, как описано выше для Вир/а1.

Жду подсказок и соображений.

3 комментария


  1. С точки зрения решения задачи прототипирования, то лучше как раз-таки оставить приблизительно как есть. Можно хоть всё собирать статически, а внутри делать «загрузку»/»выгрузку».

    Если же исходить из того, что это не только прототип, а ещё и ограниченно применимый инструмент на время, то с точки зрения решения частного в рамках большой задачи, то однозначно нужно идти путём создания своего целевого представления(3.2). Это не обязательно слишком трудоёмко и непроизводительно, так как такой выбор не запрещает транслировать в тот же С в качестве подпорки.

    Ну и не факт, что все существующие VM окажутся для задачи плохо пригодными, просто это требует исследования. Например, кто знает, если бы подошёл Wasm, то это могло бы решить очень многие вопросы.

    Ответить

      1. Если внимательно присмотреться, то C, раз трансляция через него подходит, как раз и представляет собой вариацию 3.1. Да и многие «аппаратные» архитектуры уже давно являются «V»M в том или ином виде.
        С другой стороны, это показывает, как на самом деле сложно добиться переиспользования. Ведь ваше 3.2 для многих других проектов будет 3.1.

        Ответить

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *