bmstu-iu9 / bmstu-iu9/refal-5-lambda
`strip` портит exe-шники
- Dominant language
- C++
- Stars
- 97
- Forks
- 40
- PR merge metrics
- No merged PRs in 30d
Description
Проблема
=======
В пулл реквесте #363 @cab404 обнаружил, что утилита `strip` на Linux портит исполнимые файлы. Pull request посвящён создания пакета Рефала-5λ в пакетном менеджере Nix.
Действительно, исполнимый файл состоит из интерпретатора и приписанного к нему исполняемого кода, причём интерпретируемый код должен начинаться со смещения, кратного `4096`, т.е. устройство подобно устройству SFX-архива.
Команда `strip` не подозревает об этой структуре исполнимого файла и из префикса-интерпретатора не только удаляет секции с отладочной информацией, но и просто дропает весь хвост с интерпретируемым кодом.
Обрезание осуществляется в процессе подготовки пакета соответствующими утилитами.
Обходной путь
==========
@cab404 добавил в скрипт сборки опцию, запрещающую `strip`’ать исполнимые файлы:
https://github.com/bmstu-iu9/refal-5-lambda/compare/fa1f8f862a73e7ca6194f67cd146ca158919d70e..ad842a440995f997cc04a014a46daa7c1922bbac
https://github.com/bmstu-iu9/refal-5-lambda/blob/ad842a440995f997cc04a014a46daa7c1922bbac/flake.nix#L17-L19
Требования к решению и другие размышления
================================
Ожидаемое поведение должно быть таким:
```
$ rlc program.ref
* Compiling program.ref:
** Compilation suceeded **
$ ./program
Hello!
$ strip program
$ ./program
Hello!
```
Если реализовать новое API для нативных функций как #324, то сборка в режиме прямой кодогенерации (`rlc --scratch -Od program.ref`) обеспечит ожидаемое поведение, т.к. в этом режиме программы не будут содержать интерпретируемого кода. Это неплохо, но это не решает проблему программ, скомпилированных в режиме интерпретации.
Актуальная реализация режима интерпретации (префикс-интерпретатор + интерпретируемый код) имеет следующие преимущества (см. также #48):
* Она _почти_ одинаково работает на всех поддерживаемых платформах (Windows, Linux, macOS):
* Компиляция:
- вызываем компилятор C++ (можно встроить почти любой),
- к полученному exe’шнику добавляем в конец байты выравнивания для кратности 4096,
- приписываем исполнимый код,
- вызываем команду, заданную в параметре командной строки `--chmod-x-command`.¹
* Запуск:
- узнаём имя исполнимого файла обращением к ОС,²
- открываем файл при помощи стандартного `fopen()`, ищем в нём сигнатуру и загружаем интерпретируемый код.
Есть только две платформоспецифичности:
- ¹ `--chmod-x-command` устанавливается скриптом на Bash в `chmod +x`, bat-скриптом в пустую строку.
- ² Вызывать `fopen(argv[0], "rb")` нельзя, т.к. `argv[0]` на unix-подобных ОС просто содержит нулевой аргумент: если программа лежит в `PATH`, то в `argv[0]` будет лежать имя программы без пути; при запуске под отладчиком `argv[0]` может быть и пустой строкой. Поэтому приходится вызывать ту или иную API-функцию (абстрагированную как `refalrts::api::get_main_module_name()`) для определения пути к запущенному файлу.
* Компиляция в режиме интерпретации не требует компилятора C++. Дистрибутив может содержать заранее скомпилированные интерпретаторы-префиксы, к которым Рефал-5λ приписывает интерпретируемый код.
* Исполнимые файлы полностью автономные — не требуют наличия на машине ни интерпретатора, ни рантайма.
* И при этом реализация относительно проста.
Описанные выше преимущества хотелось бы сохранить. Особенно второе — независимость уже собранного компилятора Рефала-5λ от наличия компилятора C++ и третье — автономность исполнимых файлов.
Частные решения
============
Добавление опции `--strip` к `rlc`
-------------------------------------
Можно добавить опции `--strip` и `--strip-command=…` к компилятору. Вторая опция задаёт имя утилиты `strip` (непустое на unix-like или при использовании MinGW GCC, пустое в остальных случаях), первая включает эту команду после создания префикса и до записывания интерпретируемого кода (если `--strip-command=…` пусто, то ничего не делает).
Так можно стрипать исполнимые файлы в процессе сборки.
Решение является частным, т.к. не решает проблему с вызовом внешней `strip`. В частности, решение ничего не даёт при использовании внешнего сценария вроде создания пакета пакетным менеджером (сценарий из #363).
Добавление утилиты `rl-strip`
---------------------------------
Утилита отделяет префикс от интерпретируемого кода, стрипает его, возвращает интерпретируемый код на место.
Решение является частным по той же причине, что и предыдущее.
Нормальное решение
===============
Пока не знаю.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.