← На главную

N2901: transparent aliases дают ABI-стабильность без заморозки

08.08.2026 07:36 · hackernews

Анти-ABI-настроения сами по себе ничего не меняют. Даже если ты прав и ABI-стабильность душит язык, компиляторы и стандартные библиотеки всё равно будут оглядываться на бинарную совместимость. Нужен способ сохранить стабильность, но не замораживать поведение навсегда.

В C это особенно больно, потому что линкер не проверяет типы. Достаточно поменять у функции do_stuff параметр long long на __int128_t, и вот уже на x86_64 аргумент едет не в одном rdi, а в rdi и rsi, а возврат занимает rax и rdx. Если объявление и определение разъехались, линкер спокойно свяжет символ do_stuff с «не тем» определением. В C++ спасает name mangling (_Z8do_stuffn), в C его нет. А когда на системе живут общие библиотеки, расхождение заголовков и реальных символов даёт не падение на ровном месте, а битые регистры, память и стек.

Последствия видны по срокам: C99 _Complex и VLA стали опциональными в C11, запрет copy-on-write в C++11 std::string докатился до дистрибутивов только к 2018/19, а realloc с нулевым размером из-за расхождений реализаций в итоге объявили undefined behavior. Комитеты тут не рулят: реализации диктуют, что можно, а что нельзя.

Решение из документа N2901 — transparent aliases. Это старый приём: NetBSD больше 25 лет использует assembly labels, MSVC умеет #pragma comment(linker, "/export:..."), GCC и Arm Keil — __attribute__((alias(...))), musl через weak_alias подделывает glibc-символы. N2901 оформляет это как стандартную фичу. Синтаксис: _Alias g = f; — и в ассемблере не остаётся упоминания g, только вызовы f. С оптимизациями и без. Не появляется новый символ, не добавляется накладных расходов.

Исходное имя функции отделяется от имени символа в бинарнике. Библиотека может хранить внутри __do_work_v0 и __do_work_v1, а наружу отдавать одно и то же исходное имя do_work через макрос. Старые приложения продолжают звать старую версию символа, новые получают новую семантику. ABI остаётся стабильным, но язык не застревает в прошлом. Решение проверено в Clang на трёх основных ОС.

Читать оригинал →